animejs 4.2.0-beta.0 → 4.2.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.
Files changed (73) hide show
  1. package/README.md +6 -1
  2. package/dist/bundles/anime.esm.js +448 -260
  3. package/dist/bundles/anime.esm.min.js +1 -1
  4. package/dist/bundles/anime.umd.js +449 -261
  5. package/dist/bundles/anime.umd.min.js +1 -1
  6. package/dist/modules/animatable/animatable.cjs +2 -2
  7. package/dist/modules/animatable/animatable.js +1 -1
  8. package/dist/modules/animation/animation.cjs +21 -14
  9. package/dist/modules/animation/animation.d.ts +0 -2
  10. package/dist/modules/animation/animation.js +20 -13
  11. package/dist/modules/core/consts.cjs +6 -1
  12. package/dist/modules/core/consts.d.ts +2 -0
  13. package/dist/modules/core/consts.js +5 -2
  14. package/dist/modules/core/globals.cjs +1 -0
  15. package/dist/modules/core/globals.js +1 -0
  16. package/dist/modules/core/render.cjs +3 -1
  17. package/dist/modules/core/render.js +3 -1
  18. package/dist/modules/core/styles.cjs +7 -7
  19. package/dist/modules/core/styles.js +9 -9
  20. package/dist/modules/core/values.cjs +16 -5
  21. package/dist/modules/core/values.js +18 -7
  22. package/dist/modules/draggable/draggable.cjs +16 -16
  23. package/dist/modules/draggable/draggable.d.ts +1 -1
  24. package/dist/modules/draggable/draggable.js +11 -11
  25. package/dist/modules/easings/{cubic-bezier.cjs → cubic-bezier/index.cjs} +3 -3
  26. package/dist/modules/easings/{cubic-bezier.d.ts → cubic-bezier/index.d.ts} +1 -1
  27. package/dist/modules/easings/{cubic-bezier.js → cubic-bezier/index.js} +3 -3
  28. package/dist/modules/easings/eases/index.cjs +14 -0
  29. package/dist/modules/easings/eases/index.d.ts +1 -0
  30. package/dist/modules/{spring → easings/eases}/index.js +2 -2
  31. package/dist/modules/easings/{eases.cjs → eases/parser.cjs} +68 -26
  32. package/dist/modules/easings/{eases.d.ts → eases/parser.d.ts} +31 -17
  33. package/dist/modules/easings/{eases.js → eases/parser.js} +59 -20
  34. package/dist/modules/easings/index.cjs +14 -12
  35. package/dist/modules/easings/index.d.ts +6 -6
  36. package/dist/modules/easings/index.js +6 -6
  37. package/dist/modules/easings/{irregular.cjs → irregular/index.cjs} +4 -4
  38. package/dist/modules/easings/{irregular.d.ts → irregular/index.d.ts} +1 -1
  39. package/dist/modules/easings/{irregular.js → irregular/index.js} +3 -3
  40. package/dist/modules/easings/{linear.cjs → linear/index.cjs} +3 -3
  41. package/dist/modules/easings/{linear.d.ts → linear/index.d.ts} +1 -1
  42. package/dist/modules/easings/{linear.js → linear/index.js} +3 -3
  43. package/dist/modules/easings/spring/index.cjs +255 -0
  44. package/dist/modules/{spring/spring.d.ts → easings/spring/index.d.ts} +21 -5
  45. package/dist/modules/easings/spring/index.js +251 -0
  46. package/dist/modules/easings/{steps.cjs → steps/index.cjs} +2 -2
  47. package/dist/modules/easings/{steps.d.ts → steps/index.d.ts} +1 -1
  48. package/dist/modules/easings/{steps.js → steps/index.js} +2 -2
  49. package/dist/modules/events/scroll.cjs +10 -6
  50. package/dist/modules/events/scroll.d.ts +2 -0
  51. package/dist/modules/events/scroll.js +9 -5
  52. package/dist/modules/index.cjs +14 -15
  53. package/dist/modules/index.d.ts +0 -1
  54. package/dist/modules/index.js +6 -7
  55. package/dist/modules/timeline/timeline.cjs +2 -2
  56. package/dist/modules/timeline/timeline.js +1 -1
  57. package/dist/modules/types/index.d.ts +30 -13
  58. package/dist/modules/utils/stagger.cjs +3 -3
  59. package/dist/modules/utils/stagger.js +2 -2
  60. package/dist/modules/waapi/composition.cjs +10 -4
  61. package/dist/modules/waapi/composition.d.ts +1 -1
  62. package/dist/modules/waapi/composition.js +10 -4
  63. package/dist/modules/waapi/waapi.cjs +50 -31
  64. package/dist/modules/waapi/waapi.d.ts +4 -2
  65. package/dist/modules/waapi/waapi.js +51 -32
  66. package/package.json +46 -10
  67. package/dist/modules/easings/parser.cjs +0 -59
  68. package/dist/modules/easings/parser.d.ts +0 -21
  69. package/dist/modules/easings/parser.js +0 -55
  70. package/dist/modules/spring/index.cjs +0 -15
  71. package/dist/modules/spring/index.d.ts +0 -1
  72. package/dist/modules/spring/spring.cjs +0 -133
  73. package/dist/modules/spring/spring.js +0 -130
@@ -17,6 +17,7 @@
17
17
  * @property {Number|Boolean} [loop]
18
18
  * @property {Boolean} [reversed]
19
19
  * @property {Boolean} [alternate]
20
+ * @property {Boolean} [persist]
20
21
  * @property {Boolean|ScrollObserver} [autoplay]
21
22
  * @property {Number|FunctionValue} [duration]
22
23
  * @property {Number|FunctionValue} [delay]
@@ -24,13 +25,13 @@
24
25
  * @property {EasingParam} [ease]
25
26
  * @property {'none'|'replace'|'blend'|compositionTypes} [composition]
26
27
  * @property {(v: any) => any} [modifier]
27
- * @property {(tickable: Tickable) => void} [onBegin]
28
- * @property {(tickable: Tickable) => void} [onBeforeUpdate]
29
- * @property {(tickable: Tickable) => void} [onUpdate]
30
- * @property {(tickable: Tickable) => void} [onLoop]
31
- * @property {(tickable: Tickable) => void} [onPause]
32
- * @property {(tickable: Tickable) => void} [onComplete]
33
- * @property {(renderable: Renderable) => void} [onRender]
28
+ * @property {Callback<Tickable>} [onBegin]
29
+ * @property {Callback<Tickable>} [onBeforeUpdate]
30
+ * @property {Callback<Tickable>} [onUpdate]
31
+ * @property {Callback<Tickable>} [onLoop]
32
+ * @property {Callback<Tickable>} [onPause]
33
+ * @property {Callback<Tickable>} [onComplete]
34
+ * @property {Callback<Renderable>} [onRender]
34
35
  */
35
36
 
36
37
  /** @typedef {JSAnimation|Timeline} Renderable */
@@ -86,7 +87,11 @@
86
87
  */
87
88
 
88
89
  /**
89
- * @typedef {('linear'|'linear(x1, x2 25%, x3)'|'in'|'out'|'inOut'|'inQuad'|'outQuad'|'inOutQuad'|'inCubic'|'outCubic'|'inOutCubic'|'inQuart'|'outQuart'|'inOutQuart'|'inQuint'|'outQuint'|'inOutQuint'|'inSine'|'outSine'|'inOutSine'|'inCirc'|'outCirc'|'inOutCirc'|'inExpo'|'outExpo'|'inOutExpo'|'inBounce'|'outBounce'|'inOutBounce'|'inBack'|'outBack'|'inOutBack'|'inElastic'|'outElastic'|'inOutElastic'|'irregular'|'cubicBezier'|'steps'|'in(p = 1.675)'|'out(p = 1.675)'|'inOut(p = 1.675)'|'inBack(overshoot = 1.70158)'|'outBack(overshoot = 1.70158)'|'inOutBack(overshoot = 1.70158)'|'inElastic(amplitude = 1, period = .3)'|'outElastic(amplitude = 1, period = .3)'|'inOutElastic(amplitude = 1, period = .3)'|'irregular(length = 10, randomness = 1)'|'cubicBezier(x1, y1, x2, y2)'|'steps(steps = 10)')} EaseStringParamNames
90
+ * @typedef {('linear'|'none'|'in'|'out'|'inOut'|'inQuad'|'outQuad'|'inOutQuad'|'inCubic'|'outCubic'|'inOutCubic'|'inQuart'|'outQuart'|'inOutQuart'|'inQuint'|'outQuint'|'inOutQuint'|'inSine'|'outSine'|'inOutSine'|'inCirc'|'outCirc'|'inOutCirc'|'inExpo'|'outExpo'|'inOutExpo'|'inBounce'|'outBounce'|'inOutBounce'|'inBack'|'outBack'|'inOutBack'|'inElastic'|'outElastic'|'inOutElastic'|'out(p = 1.675)'|'inOut(p = 1.675)'|'inBack(overshoot = 1.7)'|'outBack(overshoot = 1.7)'|'inOutBack(overshoot = 1.7)'|'inElastic(amplitude = 1, period = .3)'|'outElastic(amplitude = 1, period = .3)'|'inOutElastic(amplitude = 1, period = .3)')} EaseStringParamNames
91
+ */
92
+
93
+ /**
94
+ * @typedef {('ease'|'ease-in'|'ease-out'|'ease-in-out'|'linear(0, 0.25, 1)'|'steps'|'steps(6, start)'|'step-start'|'step-end'|'cubic-bezier(0.42, 0, 1, 1)') } WAAPIEaseStringParamNames
90
95
  */
91
96
 
92
97
  /**
@@ -97,7 +102,7 @@
97
102
 
98
103
  /**
99
104
  * @callback BackEasing
100
- * @param {Number|String} [overshoot=1.70158]
105
+ * @param {Number|String} [overshoot=1.7]
101
106
  * @return {EasingFunction}
102
107
  */
103
108
 
@@ -113,6 +118,7 @@
113
118
  // A hack to get both ease names suggestions AND allow any strings
114
119
  // https://github.com/microsoft/TypeScript/issues/29729#issuecomment-460346421
115
120
  /** @typedef {(String & {})|EaseStringParamNames|EasingFunction|Spring} EasingParam */
121
+ /** @typedef {(String & {})|EaseStringParamNames|WAAPIEaseStringParamNames|EasingFunction|Spring} WAAPIEasingParam */
116
122
 
117
123
  // Spring types
118
124
 
@@ -122,6 +128,9 @@
122
128
  * @property {Number} [stiffness=100] - Stiffness, default 100
123
129
  * @property {Number} [damping=10] - Damping, default 10
124
130
  * @property {Number} [velocity=0] - Initial velocity, default 0
131
+ * @property {Number} [bounce=0] - Initial bounce, default 0
132
+ * @property {Number} [duration=0] - The perceived duration, default 0
133
+ * @property {Callback<JSAnimation>} [onComplete] - Callback function called when the spring currentTime hits the perceived duration
125
134
  */
126
135
 
127
136
  // Callback types
@@ -219,6 +228,7 @@
219
228
  * @property {Number} _isOverlapped
220
229
  * @property {Number} _isOverridden
221
230
  * @property {Number} _renderTransforms
231
+ * @property {String} _inlineValue
222
232
  * @property {Tween} _prevRep
223
233
  * @property {Tween} _nextRep
224
234
  * @property {Tween} _prevAdd
@@ -376,7 +386,7 @@
376
386
  */
377
387
 
378
388
  /**
379
- * @typedef {(animation: WAAPIAnimation) => void} WAAPICallback
389
+ * @typedef {Callback<WAAPIAnimation>} WAAPICallback
380
390
  */
381
391
 
382
392
  /**
@@ -385,7 +395,7 @@
385
395
  * @property {WAAPIKeyframeValue} [from]
386
396
  * @property {Number|WAAPIFunctionValue} [duration]
387
397
  * @property {Number|WAAPIFunctionValue} [delay]
388
- * @property {EasingParam} [ease]
398
+ * @property {WAAPIEasingParam} [ease]
389
399
  * @property {CompositeOperation} [composition]
390
400
  */
391
401
 
@@ -398,13 +408,14 @@
398
408
  * @property {Number} [playbackRate]
399
409
  * @property {Number|WAAPIFunctionValue} [duration]
400
410
  * @property {Number|WAAPIFunctionValue} [delay]
401
- * @property {EasingParam} [ease]
411
+ * @property {WAAPIEasingParam} [ease]
402
412
  * @property {CompositeOperation} [composition]
413
+ * @property {Boolean} [persist]
403
414
  * @property {WAAPICallback} [onComplete]
404
415
  */
405
416
 
406
417
  /**
407
- * @typedef {Record<String, WAAPIKeyframeValue | WAAPIAnimationOptions | Boolean | ScrollObserver | WAAPICallback | EasingParam | WAAPITweenOptions> & WAAPIAnimationOptions} WAAPIAnimationParams
418
+ * @typedef {Record<String, WAAPIKeyframeValue | WAAPIAnimationOptions | Boolean | ScrollObserver | WAAPICallback | WAAPIEasingParam | WAAPITweenOptions> & WAAPIAnimationOptions} WAAPIAnimationParams
408
419
  */
409
420
 
410
421
  // Animatable types
@@ -682,6 +693,8 @@ const maxFps = 120;
682
693
  // Strings
683
694
 
684
695
  const emptyString = '';
696
+ const cssVarPrefix = 'var(';
697
+
685
698
  const shortTransforms = /*#__PURE__*/ (() => {
686
699
  const map = new Map();
687
700
  map.set('x', 'translateX');
@@ -705,9 +718,9 @@ const validTransforms = [
705
718
  'skew',
706
719
  'skewX',
707
720
  'skewY',
708
- 'perspective',
709
721
  'matrix',
710
722
  'matrix3d',
723
+ 'perspective',
711
724
  ];
712
725
 
713
726
  const transformsFragmentStrings = /*#__PURE__*/ validTransforms.reduce((a, v) => ({...a, [v]: v + '('}), {});
@@ -731,6 +744,7 @@ const unitsExecRgx = /^([-+]?\d*\.?\d+(?:e[-+]?\d+)?)([a-z]+|%)$/i;
731
744
  const lowerCaseRgx = /([a-z])([A-Z])/g;
732
745
  const transformsExecRgx = /(\w+)(\([^)]+\)+)/g; // Match inline transforms with cacl() values, returns the value wrapped in ()
733
746
  const relativeValuesExecRgx = /(\*=|\+=|-=)/;
747
+ const cssVariableMatchRgx = /var\(\s*(--[\w-]+)(?:\s*,\s*([^)]+))?\s*\)/;
734
748
 
735
749
 
736
750
 
@@ -745,6 +759,7 @@ const defaults = {
745
759
  reversed: false,
746
760
  alternate: false,
747
761
  autoplay: true,
762
+ persist: false,
748
763
  duration: K,
749
764
  delay: 0,
750
765
  loopDelay: 0,
@@ -1168,19 +1183,30 @@ const setValue = (targetValue, defaultValue) => {
1168
1183
  * @return {any}
1169
1184
  */
1170
1185
  const getFunctionValue = (value, target, index, total, store) => {
1186
+ let func;
1171
1187
  if (isFnc(value)) {
1172
- const func = () => {
1188
+ func = () => {
1173
1189
  const computed = /** @type {Function} */(value)(target, index, total);
1174
1190
  // Fallback to 0 if the function returns undefined / NaN / null / false / 0
1175
1191
  return !isNaN(+computed) ? +computed : computed || 0;
1176
1192
  };
1177
- if (store) {
1178
- store.func = func;
1179
- }
1180
- return func();
1193
+ } else if (isStr(value) && stringStartsWith(value, cssVarPrefix)) {
1194
+ func = () => {
1195
+ const match = value.match(cssVariableMatchRgx);
1196
+ const cssVarName = match[1];
1197
+ const fallbackValue = match[2];
1198
+ let computed = getComputedStyle(/** @type {HTMLElement} */(target))?.getPropertyValue(cssVarName);
1199
+ // Use fallback if CSS variable is not set or empty
1200
+ if ((!computed || computed.trim() === emptyString) && fallbackValue) {
1201
+ computed = fallbackValue.trim();
1202
+ }
1203
+ return computed || 0;
1204
+ };
1181
1205
  } else {
1182
1206
  return value;
1183
1207
  }
1208
+ if (store) store.func = func;
1209
+ return func();
1184
1210
  };
1185
1211
 
1186
1212
  /**
@@ -1587,7 +1613,9 @@ const render = (tickable, time, muteCallbacks, internalRender, tickMode) => {
1587
1613
  // Handle setters on timeline differently and allow re-trigering the onComplete callback when seeking backwards
1588
1614
  if (parent && isSetter) {
1589
1615
  if (!muteCallbacks && (
1590
- (parent.began && !isRunningBackwards && tickableAbsoluteTime >= duration && !completed) ||
1616
+ // (tickableAbsoluteTime > 0 instead) of (tickableAbsoluteTime >= duration) to prevent floating point precision issues
1617
+ // see: https://github.com/juliangarnier/anime/issues/1088
1618
+ (parent.began && !isRunningBackwards && tickableAbsoluteTime > 0 && !completed) ||
1591
1619
  (isRunningBackwards && tickableAbsoluteTime <= minValue && completed)
1592
1620
  )) {
1593
1621
  tickable.onComplete(/** @type {CallbackArgument} */(tickable));
@@ -1689,12 +1717,11 @@ const tick = (tickable, time, muteCallbacks, internalRender, tickMode) => {
1689
1717
  }
1690
1718
  };
1691
1719
 
1692
- const propertyNamesCache = {};
1693
-
1694
1720
 
1695
1721
 
1696
1722
 
1697
1723
 
1724
+ const propertyNamesCache = {};
1698
1725
 
1699
1726
  /**
1700
1727
  * @param {String} propertyName
@@ -1742,10 +1769,11 @@ const cleanInlineStyles = renderable => {
1742
1769
  const tweenTarget = tween.target;
1743
1770
  if (tweenTarget[isDomSymbol]) {
1744
1771
  const targetStyle = /** @type {DOMTarget} */(tweenTarget).style;
1745
- const originalInlinedValue = animation._inlineStyles[tweenProperty];
1772
+ const originalInlinedValue = tween._inlineValue;
1773
+ const tweenHadNoInlineValue = isNil(originalInlinedValue) || originalInlinedValue === emptyString;
1746
1774
  if (tween._tweenType === tweenTypes.TRANSFORM) {
1747
1775
  const cachedTransforms = tweenTarget[transformsSymbol];
1748
- if (isUnd(originalInlinedValue) || originalInlinedValue === emptyString) {
1776
+ if (tweenHadNoInlineValue) {
1749
1777
  delete cachedTransforms[tweenProperty];
1750
1778
  } else {
1751
1779
  cachedTransforms[tweenProperty] = originalInlinedValue;
@@ -1762,8 +1790,8 @@ const cleanInlineStyles = renderable => {
1762
1790
  }
1763
1791
  }
1764
1792
  } else {
1765
- if (isUnd(originalInlinedValue) || originalInlinedValue === emptyString) {
1766
- targetStyle.removeProperty(tweenProperty);
1793
+ if (tweenHadNoInlineValue) {
1794
+ targetStyle.removeProperty(toLowerCase(tweenProperty));
1767
1795
  } else {
1768
1796
  targetStyle[tweenProperty] = originalInlinedValue;
1769
1797
  }
@@ -3048,6 +3076,7 @@ const none = t => t;
3048
3076
 
3049
3077
 
3050
3078
 
3079
+
3051
3080
  /** @type {PowerEasing} */
3052
3081
  const easeInPower = (p = 1.68) => t => pow(t, +p);
3053
3082
 
@@ -3065,154 +3094,6 @@ const easeTypes = {
3065
3094
  outIn: easeIn => t => t < .5 ? (1 - easeIn(1 - t * 2)) / 2 : (easeIn(t * 2 - 1) + 1) / 2,
3066
3095
  };
3067
3096
 
3068
- /**
3069
- * @param {String} string
3070
- * @param {Record<String, EasingFunctionWithParams|EasingFunction>} easesFunctions
3071
- * @param {Object} easesLookups
3072
- * @return {EasingFunction}
3073
- */
3074
- const parseEaseString = (string, easesFunctions, easesLookups) => {
3075
- if (easesLookups[string]) return easesLookups[string];
3076
- if (string.indexOf('(') <= -1) {
3077
- const hasParams = easeTypes[string] || string.includes('Back') || string.includes('Elastic');
3078
- const parsedFn = /** @type {EasingFunction} */(hasParams ? /** @type {EasingFunctionWithParams} */(easesFunctions[string])() : easesFunctions[string]);
3079
- return parsedFn ? easesLookups[string] = parsedFn : none;
3080
- } else {
3081
- const split = string.slice(0, -1).split('(');
3082
- const parsedFn = /** @type {EasingFunctionWithParams} */(easesFunctions[split[0]]);
3083
- return parsedFn ? easesLookups[string] = parsedFn(...split[1].split(',')) : none;
3084
- }
3085
- };
3086
-
3087
-
3088
-
3089
- /**
3090
- * Cubic Bezier solver adapted from https://github.com/gre/bezier-easing
3091
- * (c) 2014 Gaëtan Renaudeau
3092
- */
3093
-
3094
- /**
3095
- * @param {Number} aT
3096
- * @param {Number} aA1
3097
- * @param {Number} aA2
3098
- * @return {Number}
3099
- */
3100
- const calcBezier = (aT, aA1, aA2) => (((1 - 3 * aA2 + 3 * aA1) * aT + (3 * aA2 - 6 * aA1)) * aT + (3 * aA1)) * aT;
3101
-
3102
- /**
3103
- * @param {Number} aX
3104
- * @param {Number} mX1
3105
- * @param {Number} mX2
3106
- * @return {Number}
3107
- */
3108
- const binarySubdivide = (aX, mX1, mX2) => {
3109
- let aA = 0, aB = 1, currentX, currentT, i = 0;
3110
- do {
3111
- currentT = aA + (aB - aA) / 2;
3112
- currentX = calcBezier(currentT, mX1, mX2) - aX;
3113
- if (currentX > 0) {
3114
- aB = currentT;
3115
- } else {
3116
- aA = currentT;
3117
- }
3118
- } while (abs(currentX) > .0000001 && ++i < 100);
3119
- return currentT;
3120
- };
3121
-
3122
- /**
3123
- * @param {Number} [mX1] The x coordinate of the first point
3124
- * @param {Number} [mY1] The y coordinate of the first point
3125
- * @param {Number} [mX2] The x coordinate of the second point
3126
- * @param {Number} [mY2] The y coordinate of the second point
3127
- * @return {EasingFunction}
3128
- */
3129
-
3130
- const cubicBezier = (mX1 = 0.5, mY1 = 0.0, mX2 = 0.5, mY2 = 1.0) => (mX1 === mY1 && mX2 === mY2) ? none :
3131
- t => t === 0 || t === 1 ? t :
3132
- calcBezier(binarySubdivide(t, mX1, mX2), mY1, mY2);
3133
-
3134
-
3135
-
3136
- /**
3137
- * Steps ease implementation https://developer.mozilla.org/fr/docs/Web/CSS/transition-timing-function
3138
- * Only covers 'end' and 'start' jumpterms
3139
- * @param {Number} steps
3140
- * @param {Boolean} [fromStart]
3141
- * @return {EasingFunction}
3142
- */
3143
- const steps = (steps = 10, fromStart) => {
3144
- const roundMethod = fromStart ? ceil : floor;
3145
- return t => roundMethod(clamp$1(t, 0, 1) * steps) * (1 / steps);
3146
- };
3147
-
3148
-
3149
-
3150
- /**
3151
- * Without parameters, the linear function creates a non-eased transition.
3152
- * Parameters, if used, creates a piecewise linear easing by interpolating linearly between the specified points.
3153
- *
3154
- * @param {...(String|Number)} args - Points
3155
- * @return {EasingFunction}
3156
- */
3157
- const linear = (...args) => {
3158
- const argsLength = args.length;
3159
- if (!argsLength) return none;
3160
- const totalPoints = argsLength - 1;
3161
- const firstArg = args[0];
3162
- const lastArg = args[totalPoints];
3163
- const xPoints = [0];
3164
- const yPoints = [parseNumber(firstArg)];
3165
- for (let i = 1; i < totalPoints; i++) {
3166
- const arg = args[i];
3167
- const splitValue = isStr(arg) ?
3168
- /** @type {String} */(arg).trim().split(' ') :
3169
- [arg];
3170
- const value = splitValue[0];
3171
- const percent = splitValue[1];
3172
- xPoints.push(!isUnd(percent) ? parseNumber(percent) / 100 : i / totalPoints);
3173
- yPoints.push(parseNumber(value));
3174
- }
3175
- yPoints.push(parseNumber(lastArg));
3176
- xPoints.push(1);
3177
- return function easeLinear(t) {
3178
- for (let i = 1, l = xPoints.length; i < l; i++) {
3179
- const currentX = xPoints[i];
3180
- if (t <= currentX) {
3181
- const prevX = xPoints[i - 1];
3182
- const prevY = yPoints[i - 1];
3183
- return prevY + (yPoints[i] - prevY) * (t - prevX) / (currentX - prevX);
3184
- }
3185
- }
3186
- return yPoints[yPoints.length - 1];
3187
- }
3188
- };
3189
-
3190
-
3191
-
3192
- /**
3193
- * Generate random steps
3194
- * @param {Number} [length] - The number of steps
3195
- * @param {Number} [randomness] - How strong the randomness is
3196
- * @return {EasingFunction}
3197
- */
3198
- const irregular = (length = 10, randomness = 1) => {
3199
- const values = [0];
3200
- const total = length - 1;
3201
- for (let i = 1; i < total; i++) {
3202
- const previousValue = values[i - 1];
3203
- const spacing = i / total;
3204
- const segmentEnd = (i + 1) / total;
3205
- const randomVariation = spacing + (segmentEnd - spacing) * Math.random();
3206
- // Mix the even spacing and random variation based on the randomness parameter
3207
- const randomValue = spacing * (1 - randomness) + randomVariation * randomness;
3208
- values.push(clamp$1(randomValue, previousValue, 1));
3209
- }
3210
- values.push(1);
3211
- return linear(...values);
3212
- };
3213
-
3214
-
3215
-
3216
3097
  /**
3217
3098
  * Easing functions adapted and simplified from https://robertpenner.com/easing/
3218
3099
  * (c) 2001 Robert Penner
@@ -3241,7 +3122,7 @@ const easeInFunctions = {
3241
3122
  return 1 / pow(4, 3 - b) - 7.5625 * pow((pow2 * 3 - 2) / 22 - t, 2);
3242
3123
  },
3243
3124
  /** @type {BackEasing} */
3244
- Back: (overshoot = 1.70158) => t => (+overshoot + 1) * t * t * t - +overshoot * t * t,
3125
+ Back: (overshoot = 1.7) => t => (+overshoot + 1) * t * t * t - +overshoot * t * t,
3245
3126
  /** @type {ElasticEasing} */
3246
3127
  Elastic: (amplitude = 1, period = .3) => {
3247
3128
  const a = clamp$1(+amplitude, 1, 10);
@@ -3254,10 +3135,8 @@ const easeInFunctions = {
3254
3135
 
3255
3136
  /**
3256
3137
  * @typedef {Object} EasesFunctions
3257
- * @property {typeof linear} linear
3258
- * @property {typeof irregular} irregular
3259
- * @property {typeof steps} steps
3260
- * @property {typeof cubicBezier} cubicBezier
3138
+ * @property {typeof none} linear
3139
+ * @property {typeof none} none
3261
3140
  * @property {PowerEasing} in
3262
3141
  * @property {PowerEasing} out
3263
3142
  * @property {PowerEasing} inOut
@@ -3305,7 +3184,7 @@ const easeInFunctions = {
3305
3184
  */
3306
3185
 
3307
3186
  const eases = (/*#__PURE__ */ (() => {
3308
- const list = { linear, irregular, steps, cubicBezier };
3187
+ const list = { linear: none, none: none };
3309
3188
  for (let type in easeTypes) {
3310
3189
  for (let name in easeInFunctions) {
3311
3190
  const easeIn = easeInFunctions[name];
@@ -3321,15 +3200,43 @@ const eases = (/*#__PURE__ */ (() => {
3321
3200
  })());
3322
3201
 
3323
3202
  /** @type {Record<String, EasingFunction>} */
3324
- const JSEasesLookups = { linear: none };
3203
+ const easesLookups = { linear: none, none: none };
3204
+
3205
+ /**
3206
+ * @param {String} string
3207
+ * @return {EasingFunction}
3208
+ */
3209
+ const parseEaseString = (string) => {
3210
+ if (easesLookups[string]) return easesLookups[string];
3211
+ if (string.indexOf('(') <= -1) {
3212
+ const hasParams = easeTypes[string] || string.includes('Back') || string.includes('Elastic');
3213
+ const parsedFn = /** @type {EasingFunction} */(hasParams ? /** @type {EasingFunctionWithParams} */(eases[string])() : eases[string]);
3214
+ return parsedFn ? easesLookups[string] = parsedFn : none;
3215
+ } else {
3216
+ const split = string.slice(0, -1).split('(');
3217
+ const parsedFn = /** @type {EasingFunctionWithParams} */(eases[split[0]]);
3218
+ return parsedFn ? easesLookups[string] = parsedFn(...split[1].split(',')) : none;
3219
+ }
3220
+ };
3221
+
3222
+ const deprecated = ['steps(', 'irregular(', 'linear(', 'cubicBezier('];
3325
3223
 
3326
3224
  /**
3327
3225
  * @param {EasingParam} ease
3328
3226
  * @return {EasingFunction}
3329
3227
  */
3330
- const parseEase = ease => isFnc(ease) ? ease :
3331
- isStr(ease) ? parseEaseString(/** @type {String} */(ease), eases, JSEasesLookups) :
3332
- none;
3228
+ const parseEase = ease => {
3229
+ if (isStr(ease)) {
3230
+ for (let i = 0, l = deprecated.length; i < l; i++) {
3231
+ if (stringStartsWith(ease, deprecated[i])) {
3232
+ console.warn(`String syntax for \`ease: "${ease}"\` has been removed from the core and replaced by importing and passing the easing function directly: \`ease: ${ease}\``);
3233
+ return none;
3234
+ }
3235
+ }
3236
+ }
3237
+ const easeFunc = isFnc(ease) ? ease : isStr(ease) ? parseEaseString(/** @type {String} */(ease)) : none;
3238
+ return easeFunc;
3239
+ };
3333
3240
 
3334
3241
 
3335
3242
 
@@ -3337,6 +3244,7 @@ const parseEase = ease => isFnc(ease) ? ease :
3337
3244
  // TODO: Maybe move the objects creation to values.js and use the decompose function to create the base object
3338
3245
  const fromTargetObject = createDecomposedValueTargetObject();
3339
3246
  const toTargetObject = createDecomposedValueTargetObject();
3247
+ const inlineStylesStore = {};
3340
3248
  const toFunctionStore = { func: null };
3341
3249
  const keyframesTargetArray = [null];
3342
3250
  const fastSetValuesArray = [null, null];
@@ -3481,15 +3389,15 @@ class JSAnimation extends Timer {
3481
3389
  const animEase = animaPlaybackEase ? parseEase(animaPlaybackEase) : null;
3482
3390
  const hasSpring = !isUnd(ease) && !isUnd(/** @type {Spring} */(ease).ease);
3483
3391
  const tEasing = hasSpring ? /** @type {Spring} */(ease).ease : setValue(ease, animEase ? 'linear' : animDefaults.ease);
3484
- const tDuration = hasSpring ? /** @type {Spring} */(ease).duration : setValue(duration, animDefaults.duration);
3392
+ const tDuration = hasSpring ? /** @type {Spring} */(ease).settlingDuration : setValue(duration, animDefaults.duration);
3485
3393
  const tDelay = setValue(delay, animDefaults.delay);
3486
3394
  const tModifier = modifier || animDefaults.modifier;
3487
3395
  // If no composition is defined and the targets length is high (>= 1000) set the composition to 'none' (0) for faster tween creation
3488
3396
  const tComposition = isUnd(composition) && targetsLength >= K ? compositionTypes.none : !isUnd(composition) ? composition : animDefaults.composition;
3489
- // TODO: Do not create an empty object until we know the animation will generate inline styles
3490
- const animInlineStyles = {};
3491
3397
  // const absoluteOffsetTime = this._offset;
3492
3398
  const absoluteOffsetTime = this._offset + (parent ? parent._offset : 0);
3399
+ // This allows targeting the current animation in the spring onComplete callback
3400
+ if (hasSpring) /** @type {Spring} */(ease).parent = this;
3493
3401
 
3494
3402
  let iterationDuration = NaN;
3495
3403
  let iterationDelay = NaN;
@@ -3591,7 +3499,7 @@ class JSAnimation extends Timer {
3591
3499
  // Easing are treated differently and don't accept function based value to prevent having to pass a function wrapper that returns an other function all the time
3592
3500
  const tweenEasing = hasSpring ? /** @type {Spring} */(keyEasing).ease : keyEasing || tEasing;
3593
3501
  // Calculate default individual keyframe duration by dividing the tl of keyframes
3594
- const tweenDuration = hasSpring ? /** @type {Spring} */(keyEasing).duration : getFunctionValue(setValue(key.duration, (l > 1 ? getFunctionValue(tDuration, target, ti, tl) / l : tDuration)), target, ti, tl);
3502
+ const tweenDuration = hasSpring ? /** @type {Spring} */(keyEasing).settlingDuration : getFunctionValue(setValue(key.duration, (l > 1 ? getFunctionValue(tDuration, target, ti, tl) / l : tDuration)), target, ti, tl);
3595
3503
  // Default delay value should only be applied to the first tween
3596
3504
  const tweenDelay = getFunctionValue(setValue(key.delay, (!tweenIndex ? tDelay : 0)), target, ti, tl);
3597
3505
  const computedComposition = getFunctionValue(setValue(key.composition, tComposition), target, ti, tl);
@@ -3641,7 +3549,7 @@ class JSAnimation extends Timer {
3641
3549
  }
3642
3550
  } else {
3643
3551
  decomposeRawValue(
3644
- getOriginalAnimatableValue(target, propName, tweenType, animInlineStyles),
3552
+ getOriginalAnimatableValue(target, propName, tweenType, inlineStylesStore),
3645
3553
  decomposedOriginalValue
3646
3554
  );
3647
3555
  if (decomposedOriginalValue.t === valueTypes.UNIT) {
@@ -3659,7 +3567,7 @@ class JSAnimation extends Timer {
3659
3567
  } else {
3660
3568
  // No need to get and parse the original value if the tween is part of a timeline and has a previous sibling part of the same timeline
3661
3569
  decomposeRawValue(parent && prevSibling && prevSibling.parent.parent === parent ? prevSibling._value :
3662
- getOriginalAnimatableValue(target, propName, tweenType, animInlineStyles), toTargetObject);
3570
+ getOriginalAnimatableValue(target, propName, tweenType, inlineStylesStore), toTargetObject);
3663
3571
  }
3664
3572
  }
3665
3573
  if (hasFromvalue) {
@@ -3670,7 +3578,7 @@ class JSAnimation extends Timer {
3670
3578
  } else {
3671
3579
  decomposeRawValue(parent && prevSibling && prevSibling.parent.parent === parent ? prevSibling._value :
3672
3580
  // No need to get and parse the original value if the tween is part of a timeline and has a previous sibling part of the same timeline
3673
- getOriginalAnimatableValue(target, propName, tweenType, animInlineStyles), fromTargetObject);
3581
+ getOriginalAnimatableValue(target, propName, tweenType, inlineStylesStore), fromTargetObject);
3674
3582
  }
3675
3583
  }
3676
3584
  }
@@ -3679,7 +3587,7 @@ class JSAnimation extends Timer {
3679
3587
  if (fromTargetObject.o) {
3680
3588
  fromTargetObject.n = getRelativeValue(
3681
3589
  !prevSibling ? decomposeRawValue(
3682
- getOriginalAnimatableValue(target, propName, tweenType, animInlineStyles),
3590
+ getOriginalAnimatableValue(target, propName, tweenType, inlineStylesStore),
3683
3591
  decomposedOriginalValue
3684
3592
  ).n : prevSibling._toNumber,
3685
3593
  fromTargetObject.n,
@@ -3735,6 +3643,10 @@ class JSAnimation extends Timer {
3735
3643
  // Rounding is necessary here to minimize floating point errors when working in seconds
3736
3644
  const tweenUpdateDuration = round$1(+tweenDuration || minValue, 12);
3737
3645
 
3646
+ // Copy the value of the iniline style if it exist and imediatly nullify it to prevents false positive on other targets
3647
+ let inlineValue = inlineStylesStore[propName];
3648
+ if (!isNil(inlineValue)) inlineStylesStore[propName] = null;
3649
+
3738
3650
  /** @type {Tween} */
3739
3651
  const tween = {
3740
3652
  parent: this,
@@ -3766,6 +3678,7 @@ class JSAnimation extends Timer {
3766
3678
  _isOverlapped: 0,
3767
3679
  _isOverridden: 0,
3768
3680
  _renderTransforms: 0,
3681
+ _inlineValue: inlineValue,
3769
3682
  _prevRep: null, // For replaced tween
3770
3683
  _nextRep: null, // For replaced tween
3771
3684
  _prevAdd: null, // For additive tween
@@ -3868,8 +3781,6 @@ class JSAnimation extends Timer {
3868
3781
  // this._offset += parent ? iterationDelay : 0;
3869
3782
  /** @type {Number} */
3870
3783
  this.iterationDuration = iterationDuration;
3871
- /** @type {{}} */
3872
- this._inlineStyles = animInlineStyles;
3873
3784
 
3874
3785
  if (!this._autoplay && shouldTriggerRender) this.onRender(this);
3875
3786
  }
@@ -3903,6 +3814,7 @@ class JSAnimation extends Timer {
3903
3814
  if (tweenFunc) {
3904
3815
  const ogValue = getOriginalAnimatableValue(tween.target, tween.property, tween._tweenType);
3905
3816
  decomposeRawValue(ogValue, decomposedOriginalValue);
3817
+ // TODO: Check for from / to Array based values here,
3906
3818
  decomposeRawValue(tweenFunc(), toTargetObject);
3907
3819
  tween._fromNumbers = cloneArray(decomposedOriginalValue.d);
3908
3820
  tween._fromNumber = decomposedOriginalValue.n;
@@ -3912,6 +3824,8 @@ class JSAnimation extends Timer {
3912
3824
  tween._toNumber = toTargetObject.o ? getRelativeValue(decomposedOriginalValue.n, toTargetObject.n, toTargetObject.o) : toTargetObject.n;
3913
3825
  }
3914
3826
  });
3827
+ // This forces setter animations to render once
3828
+ if (this.duration === minValue) this.restart();
3915
3829
  return this;
3916
3830
  }
3917
3831
 
@@ -3954,16 +3868,18 @@ const WAAPIAnimationsLookups = {
3954
3868
  * @param {DOMTarget} $el
3955
3869
  * @param {String} [property]
3956
3870
  * @param {WAAPIAnimation} [parent]
3871
+ * @return {globalThis.Animation}
3957
3872
  */
3958
3873
  const removeWAAPIAnimation = ($el, property, parent) => {
3959
3874
  let nextLookup = WAAPIAnimationsLookups._head;
3875
+ let anim;
3960
3876
  while (nextLookup) {
3961
3877
  const next = nextLookup._next;
3962
3878
  const matchTarget = nextLookup.$el === $el;
3963
3879
  const matchProperty = !property || nextLookup.property === property;
3964
3880
  const matchParent = !parent || nextLookup.parent === parent;
3965
3881
  if (matchTarget && matchProperty && matchParent) {
3966
- const anim = nextLookup.animation;
3882
+ anim = nextLookup.animation;
3967
3883
  try { anim.commitStyles(); } catch {} anim.cancel();
3968
3884
  removeChild(WAAPIAnimationsLookups, nextLookup);
3969
3885
  const lookupParent = nextLookup.parent;
@@ -3971,8 +3887,8 @@ const removeWAAPIAnimation = ($el, property, parent) => {
3971
3887
  lookupParent._completed++;
3972
3888
  if (lookupParent.animations.length === lookupParent._completed) {
3973
3889
  lookupParent.completed = true;
3890
+ lookupParent.paused = true;
3974
3891
  if (!lookupParent.muteCallbacks) {
3975
- lookupParent.paused = true;
3976
3892
  lookupParent.onComplete(lookupParent);
3977
3893
  lookupParent._resolve(lookupParent);
3978
3894
  }
@@ -3981,6 +3897,7 @@ const removeWAAPIAnimation = ($el, property, parent) => {
3981
3897
  }
3982
3898
  nextLookup = next;
3983
3899
  }
3900
+ return anim;
3984
3901
  };
3985
3902
 
3986
3903
  /**
@@ -3989,7 +3906,7 @@ const removeWAAPIAnimation = ($el, property, parent) => {
3989
3906
  * @param {String} property
3990
3907
  * @param {PropertyIndexedKeyframes} keyframes
3991
3908
  * @param {KeyframeAnimationOptions} params
3992
- * @retun {Animation}
3909
+ * @retun {globalThis.Animation}
3993
3910
  */
3994
3911
  const addWAAPIAnimation = (parent, $el, property, keyframes, params) => {
3995
3912
  const animation = $el.animate(keyframes, params);
@@ -4004,8 +3921,11 @@ const addWAAPIAnimation = (parent, $el, property, keyframes, params) => {
4004
3921
  removeWAAPIAnimation($el, property);
4005
3922
  addChild(WAAPIAnimationsLookups, { parent, animation, $el, property, _next: null, _prev: null });
4006
3923
  const handleRemove = () => { removeWAAPIAnimation($el, property, parent); };
3924
+ animation.oncancel = handleRemove;
4007
3925
  animation.onremove = handleRemove;
4008
- animation.onfinish = handleRemove;
3926
+ if (!parent.persist) {
3927
+ animation.onfinish = handleRemove;
3928
+ }
4009
3929
  return animation;
4010
3930
  };
4011
3931
 
@@ -4633,8 +4553,10 @@ var numberImports = /*#__PURE__*/Object.freeze({
4633
4553
 
4634
4554
 
4635
4555
 
4556
+
4557
+
4636
4558
  /*
4637
- * Spring ease solver adapted from https://webkit.org/demos/spring/spring.js
4559
+ * Spring easing solver adapted from https://webkit.org/demos/spring/spring.js
4638
4560
  * (c) 2016 Webkit - Apple Inc
4639
4561
  */
4640
4562
 
@@ -4645,25 +4567,46 @@ class Spring {
4645
4567
  * @param {SpringParams} [parameters]
4646
4568
  */
4647
4569
  constructor(parameters = {}) {
4570
+ const hasBounceOrDuration = !isUnd(parameters.bounce) || !isUnd(parameters.duration);
4648
4571
  this.timeStep = .02; // Interval fed to the solver to calculate duration
4649
4572
  this.restThreshold = .0005; // Values below this threshold are considered resting position
4650
4573
  this.restDuration = 200; // Duration in ms used to check if the spring is resting after reaching restThreshold
4651
4574
  this.maxDuration = 60000; // The maximum allowed spring duration in ms (default 1 min)
4652
4575
  this.maxRestSteps = this.restDuration / this.timeStep / K; // How many steps allowed after reaching restThreshold before stopping the duration calculation
4653
4576
  this.maxIterations = this.maxDuration / this.timeStep / K; // Calculate the maximum iterations allowed based on maxDuration
4654
- this.m = clamp$1(setValue(parameters.mass, 1), 0, maxSpringParamValue);
4655
- this.s = clamp$1(setValue(parameters.stiffness, 100), 1, maxSpringParamValue);
4656
- this.d = clamp$1(setValue(parameters.damping, 10), .1, maxSpringParamValue);
4577
+ this.bn = clamp$1(setValue(parameters.bounce, .5), -1, 1); // The bounce percentage between -1 and 1.
4578
+ this.pd = clamp$1(setValue(parameters.duration, 628), 10 * globals.timeScale, maxSpringParamValue * globals.timeScale); // The perceived duration
4579
+ this.m = clamp$1(setValue(parameters.mass, 1), 1, maxSpringParamValue);
4580
+ this.s = clamp$1(setValue(parameters.stiffness, 100), minValue, maxSpringParamValue);
4581
+ this.d = clamp$1(setValue(parameters.damping, 10), minValue, maxSpringParamValue);
4657
4582
  this.v = clamp$1(setValue(parameters.velocity, 0), -maxSpringParamValue, maxSpringParamValue);
4658
4583
  this.w0 = 0;
4659
4584
  this.zeta = 0;
4660
4585
  this.wd = 0;
4661
4586
  this.b = 0;
4587
+ this.completed = false;
4662
4588
  this.solverDuration = 0;
4663
- this.duration = 0;
4589
+ this.settlingDuration = 0;
4590
+ /** @type {JSAnimation} */
4591
+ this.parent = null;
4592
+ /** @type {Callback<JSAnimation>} */
4593
+ this.onComplete = parameters.onComplete || noop;
4594
+ if (hasBounceOrDuration) this.calculateSDFromBD();
4664
4595
  this.compute();
4665
4596
  /** @type {EasingFunction} */
4666
- this.ease = t => t === 0 || t === 1 ? t : this.solve(t * this.solverDuration);
4597
+ this.ease = t => {
4598
+ const currentTime = t * this.settlingDuration;
4599
+ const completed = this.completed;
4600
+ const perceivedTime = this.pd;
4601
+ if (currentTime >= perceivedTime && !completed) {
4602
+ this.completed = true;
4603
+ this.onComplete(this.parent);
4604
+ }
4605
+ if (currentTime < perceivedTime && completed) {
4606
+ this.completed = false;
4607
+ }
4608
+ return t === 0 || t === 1 ? t : this.solve(t * this.solverDuration);
4609
+ };
4667
4610
  }
4668
4611
 
4669
4612
  /** @type {EasingFunction} */
@@ -4671,23 +4614,83 @@ class Spring {
4671
4614
  const { zeta, w0, wd, b } = this;
4672
4615
  let t = time;
4673
4616
  if (zeta < 1) {
4617
+ // Underdamped
4674
4618
  t = exp(-t * zeta * w0) * (1 * cos(wd * t) + b * sin(wd * t));
4675
- } else {
4619
+ } else if (zeta === 1) {
4620
+ // Critically damped
4676
4621
  t = (1 + b * t) * exp(-t * w0);
4622
+ } else {
4623
+ // Overdamped
4624
+ // Using exponential instead of cosh and sinh functions to prevent Infinity
4625
+ // Original exp(-zeta * w0 * t) * (cosh(wd * t) + b * sinh(wd * t))
4626
+ t = ((1 + b) * exp((-zeta * w0 + wd) * t) + (1 - b) * exp((-zeta * w0 - wd) * t)) / 2;
4677
4627
  }
4678
4628
  return 1 - t;
4679
4629
  }
4680
4630
 
4631
+ calculateSDFromBD() {
4632
+ // Apple's SwiftUI perceived spring duration implementation https://developer.apple.com/videos/play/wwdc2023/10158/?time=1010
4633
+ // Equations taken from Kevin Grajeda's article https://www.kvin.me/posts/effortless-ui-spring-animations
4634
+ const pds = globals.timeScale === 1 ? this.pd / K : this.pd;
4635
+ // Mass and velocity should be set to their default values
4636
+ this.m = 1;
4637
+ this.v = 0;
4638
+ // Stiffness = (2π ÷ perceptualDuration)²
4639
+ this.s = pow((2 * PI) / pds, 2);
4640
+ if (this.bn >= 0) {
4641
+ // For bounce ≥ 0 (critically damped to underdamped)
4642
+ // damping = ((1 - bounce) × 4π) ÷ perceptualDuration
4643
+ this.d = ((1 - this.bn) * 4 * PI) / pds;
4644
+ } else {
4645
+ // For bounce < 0 (overdamped)
4646
+ // damping = 4π ÷ (perceptualDuration × (1 + bounce))
4647
+ // Note: (1 + bounce) is positive since bounce is negative
4648
+ this.d = (4 * PI) / (pds * (1 + this.bn));
4649
+ }
4650
+ this.s = round$1(clamp$1(this.s, minValue, maxSpringParamValue), 3);
4651
+ this.d = round$1(clamp$1(this.d, minValue, 300), 3); // Clamping to 300 is needed to prevent insane values in the solver
4652
+ }
4653
+
4654
+ calculateBDFromSD() {
4655
+ // Calculate perceived duration and bounce from stiffness and damping
4656
+ // Note: We assumes m = 1 and v = 0 for these calculations
4657
+ const pds = (2 * PI) / sqrt(this.s);
4658
+ this.pd = pds * (globals.timeScale === 1 ? K : 1);
4659
+ const zeta = this.d / (2 * sqrt(this.s));
4660
+ if (zeta <= 1) {
4661
+ // Critically damped to underdamped
4662
+ this.bn = 1 - (this.d * pds) / (4 * PI);
4663
+ } else {
4664
+ // Overdamped
4665
+ this.bn = (4 * PI) / (this.d * pds) - 1;
4666
+ }
4667
+ this.bn = round$1(clamp$1(this.bn, -1, 1), 3);
4668
+ this.pd = round$1(clamp$1(this.pd, 10 * globals.timeScale, maxSpringParamValue * globals.timeScale), 3);
4669
+ }
4670
+
4681
4671
  compute() {
4682
4672
  const { maxRestSteps, maxIterations, restThreshold, timeStep, m, d, s, v } = this;
4683
4673
  const w0 = this.w0 = clamp$1(sqrt(s / m), minValue, K);
4684
- const zeta = this.zeta = d / (2 * sqrt(s * m));
4685
- const wd = this.wd = zeta < 1 ? w0 * sqrt(1 - zeta * zeta) : 0;
4686
- this.b = zeta < 1 ? (zeta * w0 + -v) / wd : -v + w0;
4674
+ const bouncedZeta = this.zeta = d / (2 * sqrt(s * m));
4675
+ // Calculate wd based on damping type
4676
+ if (bouncedZeta < 1) {
4677
+ // Underdamped
4678
+ this.wd = w0 * sqrt(1 - bouncedZeta * bouncedZeta);
4679
+ this.b = (bouncedZeta * w0 + -v) / this.wd;
4680
+ } else if (bouncedZeta === 1) {
4681
+ // Critically damped
4682
+ this.wd = 0;
4683
+ this.b = -v + w0;
4684
+ } else {
4685
+ // Overdamped
4686
+ this.wd = w0 * sqrt(bouncedZeta * bouncedZeta - 1);
4687
+ this.b = (bouncedZeta * w0 + -v) / this.wd;
4688
+ }
4689
+
4687
4690
  let solverTime = 0;
4688
4691
  let restSteps = 0;
4689
4692
  let iterations = 0;
4690
- while (restSteps < maxRestSteps && iterations < maxIterations) {
4693
+ while (restSteps <= maxRestSteps && iterations <= maxIterations) {
4691
4694
  if (abs(1 - this.solve(solverTime)) < restThreshold) {
4692
4695
  restSteps++;
4693
4696
  } else {
@@ -4697,15 +4700,26 @@ class Spring {
4697
4700
  solverTime += timeStep;
4698
4701
  iterations++;
4699
4702
  }
4700
- this.duration = round$1(this.solverDuration * K, 0) * globals.timeScale;
4703
+ this.settlingDuration = round$1(this.solverDuration * K, 0) * globals.timeScale;
4701
4704
  }
4702
4705
 
4703
- get mass() {
4704
- return this.m;
4706
+ get bounce() {
4707
+ return this.bn;
4705
4708
  }
4706
4709
 
4707
- set mass(v) {
4708
- this.m = clamp$1(setValue(v, 1), 0, maxSpringParamValue);
4710
+ set bounce(v) {
4711
+ this.bn = clamp$1(setValue(v, 1), -1, 1);
4712
+ this.calculateSDFromBD();
4713
+ this.compute();
4714
+ }
4715
+
4716
+ get duration() {
4717
+ return this.pd;
4718
+ }
4719
+
4720
+ set duration(v) {
4721
+ this.pd = clamp$1(setValue(v, 1), 10 * globals.timeScale, maxSpringParamValue * globals.timeScale);
4722
+ this.calculateSDFromBD();
4709
4723
  this.compute();
4710
4724
  }
4711
4725
 
@@ -4714,7 +4728,8 @@ class Spring {
4714
4728
  }
4715
4729
 
4716
4730
  set stiffness(v) {
4717
- this.s = clamp$1(setValue(v, 100), 1, maxSpringParamValue);
4731
+ this.s = clamp$1(setValue(v, 100), minValue, maxSpringParamValue);
4732
+ this.calculateBDFromSD();
4718
4733
  this.compute();
4719
4734
  }
4720
4735
 
@@ -4723,7 +4738,17 @@ class Spring {
4723
4738
  }
4724
4739
 
4725
4740
  set damping(v) {
4726
- this.d = clamp$1(setValue(v, 10), .1, maxSpringParamValue);
4741
+ this.d = clamp$1(setValue(v, 10), minValue, maxSpringParamValue);
4742
+ this.calculateBDFromSD();
4743
+ this.compute();
4744
+ }
4745
+
4746
+ get mass() {
4747
+ return this.m;
4748
+ }
4749
+
4750
+ set mass(v) {
4751
+ this.m = clamp$1(setValue(v, 1), 1, maxSpringParamValue);
4727
4752
  this.compute();
4728
4753
  }
4729
4754
 
@@ -4741,7 +4766,18 @@ class Spring {
4741
4766
  * @param {SpringParams} [parameters]
4742
4767
  * @returns {Spring}
4743
4768
  */
4744
- const createSpring = (parameters) => new Spring(parameters);
4769
+ const spring = (parameters) => new Spring(parameters);
4770
+
4771
+ /**
4772
+ * @deprecated createSpring() is deprecated use spring() instead
4773
+ *
4774
+ * @param {SpringParams} [parameters]
4775
+ * @returns {Spring}
4776
+ */
4777
+ const createSpring = (parameters) => {
4778
+ console.warn('createSpring() is deprecated use spring() instead');
4779
+ return new Spring(parameters);
4780
+ };
4745
4781
 
4746
4782
 
4747
4783
 
@@ -4922,13 +4958,13 @@ class Draggable {
4922
4958
  /** @type {Boolean|DraggableCursorParams} */
4923
4959
  this.cursor = false;
4924
4960
  /** @type {Spring} */
4925
- this.releaseXSpring = hasSpring ? /** @type {Spring} */(ease) : createSpring({
4961
+ this.releaseXSpring = hasSpring ? /** @type {Spring} */(ease) : spring({
4926
4962
  mass: setValue(parameters.releaseMass, 1),
4927
4963
  stiffness: setValue(parameters.releaseStiffness, 80),
4928
4964
  damping: setValue(parameters.releaseDamping, 20),
4929
4965
  });
4930
4966
  /** @type {Spring} */
4931
- this.releaseYSpring = hasSpring ? /** @type {Spring} */(ease) : createSpring({
4967
+ this.releaseYSpring = hasSpring ? /** @type {Spring} */(ease) : spring({
4932
4968
  mass: setValue(parameters.releaseMass, 1),
4933
4969
  stiffness: setValue(parameters.releaseStiffness, 80),
4934
4970
  damping: setValue(parameters.releaseDamping, 20),
@@ -5645,8 +5681,8 @@ class Draggable {
5645
5681
  this.$trigger.addEventListener('touchmove', preventDefault, { passive: false });
5646
5682
  this.$trigger.addEventListener('touchend', preventDefault);
5647
5683
 
5648
-
5649
- if ((!this.disabled[0] && abs(movedX) > 3) || (!this.disabled[1] && abs(movedY) > 3)) {
5684
+ // Don't check for a miminim distance move if already dragging
5685
+ if (this.dragged || (!this.disabled[0] && abs(movedX) > 3) || (!this.disabled[1] && abs(movedY) > 3)) {
5650
5686
 
5651
5687
  this.updateTicker.resume();
5652
5688
  this.pointer[2] = this.pointer[0];
@@ -5712,8 +5748,8 @@ class Draggable {
5712
5748
  const directionX = dx === cr ? cx > cr ? -1 : 1 : cx < cl ? -1 : 1;
5713
5749
  const distanceX = round$1(cx - dx, 0);
5714
5750
  springX.velocity = disabledY && hasReleaseSpring ? distanceX ? (ds * directionX) / abs(distanceX) : 0 : pv;
5715
- const { ease, duration, restDuration } = springX;
5716
- durationX = cx === dx ? 0 : hasReleaseSpring ? duration : duration - (restDuration * globals.timeScale);
5751
+ const { ease, settlingDuration, restDuration } = springX;
5752
+ durationX = cx === dx ? 0 : hasReleaseSpring ? settlingDuration : settlingDuration - (restDuration * globals.timeScale);
5717
5753
  if (hasReleaseSpring) easeX = ease;
5718
5754
  if (durationX > longestReleaseDuration) longestReleaseDuration = durationX;
5719
5755
  }
@@ -5722,8 +5758,8 @@ class Draggable {
5722
5758
  const directionY = dy === cb ? cy > cb ? -1 : 1 : cy < ct ? -1 : 1;
5723
5759
  const distanceY = round$1(cy - dy, 0);
5724
5760
  springY.velocity = disabledX && hasReleaseSpring ? distanceY ? (ds * directionY) / abs(distanceY) : 0 : pv;
5725
- const { ease, duration, restDuration } = springY;
5726
- durationY = cy === dy ? 0 : hasReleaseSpring ? duration : duration - (restDuration * globals.timeScale);
5761
+ const { ease, settlingDuration, restDuration } = springY;
5762
+ durationY = cy === dy ? 0 : hasReleaseSpring ? settlingDuration : settlingDuration - (restDuration * globals.timeScale);
5727
5763
  if (hasReleaseSpring) easeY = ease;
5728
5764
  if (durationY > longestReleaseDuration) longestReleaseDuration = durationY;
5729
5765
  }
@@ -6576,6 +6612,8 @@ class ScrollObserver {
6576
6612
  /** @type {Boolean} */
6577
6613
  this.reverted = false;
6578
6614
  /** @type {Boolean} */
6615
+ this.ready = false;
6616
+ /** @type {Boolean} */
6579
6617
  this.completed = false;
6580
6618
  /** @type {Boolean} */
6581
6619
  this.began = false;
@@ -6585,8 +6623,6 @@ class ScrollObserver {
6585
6623
  this.forceEnter = false;
6586
6624
  /** @type {Boolean} */
6587
6625
  this.hasEntered = false;
6588
- // /** @type {Array.<Number>} */
6589
- // this.offsets = [];
6590
6626
  /** @type {Number} */
6591
6627
  this.offset = 0;
6592
6628
  /** @type {Number} */
@@ -6634,6 +6670,8 @@ class ScrollObserver {
6634
6670
  // Make sure to pause the linked object in case it's added later
6635
6671
  linked.pause();
6636
6672
  this.linked = linked;
6673
+ // Forces WAAPI Animation to persist; otherwise, they will stop syncing on finish.
6674
+ if (!isUnd(/** @type {WAAPIAnimation} */(linked))) /** @type {WAAPIAnimation} */(linked).persist = true;
6637
6675
  // Try to use a target of the linked object if no target parameters specified
6638
6676
  if (!this._params.target) {
6639
6677
  /** @type {HTMLElement} */
@@ -6673,6 +6711,8 @@ class ScrollObserver {
6673
6711
  }
6674
6712
 
6675
6713
  refresh() {
6714
+ // This flag is used to prevent running handleScroll() outside of this.refresh() with values not yet calculated
6715
+ this.ready = true;
6676
6716
  this.reverted = false;
6677
6717
  const params = this._params;
6678
6718
  this.repeat = setValue(parseScrollObserverFunctionParameter(params.repeat, this), true);
@@ -6918,8 +6958,6 @@ class ScrollObserver {
6918
6958
  const offsetStart = parsedEnterTarget + offset - parsedEnterContainer;
6919
6959
  const offsetEnd = parsedLeaveTarget + offset - parsedLeaveContainer;
6920
6960
  const scrollDelta = offsetEnd - offsetStart;
6921
- // this.offsets[0] = offsetX;
6922
- // this.offsets[1] = offsetY;
6923
6961
  this.offset = offset;
6924
6962
  this.offsetStart = offsetStart;
6925
6963
  this.offsetEnd = offsetEnd;
@@ -6938,6 +6976,7 @@ class ScrollObserver {
6938
6976
  }
6939
6977
 
6940
6978
  handleScroll() {
6979
+ if (!this.ready) return;
6941
6980
  const linked = this.linked;
6942
6981
  const sync = this.sync;
6943
6982
  const syncEase = this.syncEase;
@@ -7061,6 +7100,7 @@ class ScrollObserver {
7061
7100
  this.removeDebug();
7062
7101
  }
7063
7102
  this.reverted = true;
7103
+ this.ready = false;
7064
7104
  return this;
7065
7105
  }
7066
7106
 
@@ -7072,13 +7112,142 @@ class ScrollObserver {
7072
7112
  */
7073
7113
  const onScroll = (parameters = {}) => new ScrollObserver(parameters);
7074
7114
 
7115
+
7116
+
7117
+ /**
7118
+ * Cubic Bezier solver adapted from https://github.com/gre/bezier-easing
7119
+ * (c) 2014 Gaëtan Renaudeau
7120
+ */
7121
+
7122
+ /**
7123
+ * @param {Number} aT
7124
+ * @param {Number} aA1
7125
+ * @param {Number} aA2
7126
+ * @return {Number}
7127
+ */
7128
+ const calcBezier = (aT, aA1, aA2) => (((1 - 3 * aA2 + 3 * aA1) * aT + (3 * aA2 - 6 * aA1)) * aT + (3 * aA1)) * aT;
7129
+
7130
+ /**
7131
+ * @param {Number} aX
7132
+ * @param {Number} mX1
7133
+ * @param {Number} mX2
7134
+ * @return {Number}
7135
+ */
7136
+ const binarySubdivide = (aX, mX1, mX2) => {
7137
+ let aA = 0, aB = 1, currentX, currentT, i = 0;
7138
+ do {
7139
+ currentT = aA + (aB - aA) / 2;
7140
+ currentX = calcBezier(currentT, mX1, mX2) - aX;
7141
+ if (currentX > 0) {
7142
+ aB = currentT;
7143
+ } else {
7144
+ aA = currentT;
7145
+ }
7146
+ } while (abs(currentX) > .0000001 && ++i < 100);
7147
+ return currentT;
7148
+ };
7149
+
7150
+ /**
7151
+ * @param {Number} [mX1] The x coordinate of the first point
7152
+ * @param {Number} [mY1] The y coordinate of the first point
7153
+ * @param {Number} [mX2] The x coordinate of the second point
7154
+ * @param {Number} [mY2] The y coordinate of the second point
7155
+ * @return {EasingFunction}
7156
+ */
7157
+
7158
+ const cubicBezier = (mX1 = 0.5, mY1 = 0.0, mX2 = 0.5, mY2 = 1.0) => (mX1 === mY1 && mX2 === mY2) ? none :
7159
+ t => t === 0 || t === 1 ? t :
7160
+ calcBezier(binarySubdivide(t, mX1, mX2), mY1, mY2);
7161
+
7162
+
7163
+
7164
+ /**
7165
+ * Steps ease implementation https://developer.mozilla.org/fr/docs/Web/CSS/transition-timing-function
7166
+ * Only covers 'end' and 'start' jumpterms
7167
+ * @param {Number} steps
7168
+ * @param {Boolean} [fromStart]
7169
+ * @return {EasingFunction}
7170
+ */
7171
+ const steps = (steps = 10, fromStart) => {
7172
+ const roundMethod = fromStart ? ceil : floor;
7173
+ return t => roundMethod(clamp$1(t, 0, 1) * steps) * (1 / steps);
7174
+ };
7175
+
7176
+
7177
+
7178
+ /**
7179
+ * Without parameters, the linear function creates a non-eased transition.
7180
+ * Parameters, if used, creates a piecewise linear easing by interpolating linearly between the specified points.
7181
+ *
7182
+ * @param {...(String|Number)} args - Points
7183
+ * @return {EasingFunction}
7184
+ */
7185
+ const linear = (...args) => {
7186
+ const argsLength = args.length;
7187
+ if (!argsLength) return none;
7188
+ const totalPoints = argsLength - 1;
7189
+ const firstArg = args[0];
7190
+ const lastArg = args[totalPoints];
7191
+ const xPoints = [0];
7192
+ const yPoints = [parseNumber(firstArg)];
7193
+ for (let i = 1; i < totalPoints; i++) {
7194
+ const arg = args[i];
7195
+ const splitValue = isStr(arg) ?
7196
+ /** @type {String} */(arg).trim().split(' ') :
7197
+ [arg];
7198
+ const value = splitValue[0];
7199
+ const percent = splitValue[1];
7200
+ xPoints.push(!isUnd(percent) ? parseNumber(percent) / 100 : i / totalPoints);
7201
+ yPoints.push(parseNumber(value));
7202
+ }
7203
+ yPoints.push(parseNumber(lastArg));
7204
+ xPoints.push(1);
7205
+ return function easeLinear(t) {
7206
+ for (let i = 1, l = xPoints.length; i < l; i++) {
7207
+ const currentX = xPoints[i];
7208
+ if (t <= currentX) {
7209
+ const prevX = xPoints[i - 1];
7210
+ const prevY = yPoints[i - 1];
7211
+ return prevY + (yPoints[i] - prevY) * (t - prevX) / (currentX - prevX);
7212
+ }
7213
+ }
7214
+ return yPoints[yPoints.length - 1];
7215
+ }
7216
+ };
7217
+
7218
+
7219
+
7220
+ /**
7221
+ * Generate random steps
7222
+ * @param {Number} [length] - The number of steps
7223
+ * @param {Number} [randomness] - How strong the randomness is
7224
+ * @return {EasingFunction}
7225
+ */
7226
+ const irregular = (length = 10, randomness = 1) => {
7227
+ const values = [0];
7228
+ const total = length - 1;
7229
+ for (let i = 1; i < total; i++) {
7230
+ const previousValue = values[i - 1];
7231
+ const spacing = i / total;
7232
+ const segmentEnd = (i + 1) / total;
7233
+ const randomVariation = spacing + (segmentEnd - spacing) * Math.random();
7234
+ // Mix the even spacing and random variation based on the randomness parameter
7235
+ const randomValue = spacing * (1 - randomness) + randomVariation * randomness;
7236
+ values.push(clamp$1(randomValue, previousValue, 1));
7237
+ }
7238
+ values.push(1);
7239
+ return linear(...values);
7240
+ };
7241
+
7075
7242
  var index$3 = /*#__PURE__*/Object.freeze({
7076
7243
  __proto__: null,
7244
+ Spring: Spring,
7245
+ createSpring: createSpring,
7077
7246
  cubicBezier: cubicBezier,
7078
7247
  eases: eases,
7079
7248
  irregular: irregular,
7080
7249
  linear: linear,
7081
- none: none,
7250
+ spring: spring,
7082
7251
  steps: steps
7083
7252
  });
7084
7253
 
@@ -8134,21 +8303,11 @@ var index = /*#__PURE__*/Object.freeze({
8134
8303
  */
8135
8304
  const easingToLinear = (fn, samples = 100) => {
8136
8305
  const points = [];
8137
- for (let i = 0; i <= samples; i++) points.push(fn(i / samples));
8306
+ for (let i = 0; i <= samples; i++) points.push(round$1(fn(i / samples), 4));
8138
8307
  return `linear(${points.join(', ')})`;
8139
8308
  };
8140
8309
 
8141
- const WAAPIEasesLookups = {
8142
- in: 'ease-in',
8143
- out: 'ease-out',
8144
- inOut: 'ease-in-out',
8145
- };
8146
-
8147
- const WAAPIeases = /*#__PURE__*/(() => {
8148
- const list = {};
8149
- for (let type in easeTypes) list[type] = (/** @type {String|Number} */p) => easeTypes[type](easeInPower(p));
8150
- return /** @type {Record<String, EasingFunction>} */(list);
8151
- })();
8310
+ const WAAPIEasesLookups = {};
8152
8311
 
8153
8312
  /**
8154
8313
  * @param {EasingParam} ease
@@ -8169,9 +8328,10 @@ const parseWAAPIEasing = (ease) => {
8169
8328
  } else if (stringStartsWith(ease, 'cubicB')) {
8170
8329
  parsedEase = toLowerCase(ease);
8171
8330
  } else {
8172
- const parsed = parseEaseString(ease, WAAPIeases, WAAPIEasesLookups);
8331
+ const parsed = parseEaseString(ease);
8173
8332
  if (isFnc(parsed)) parsedEase = parsed === none ? 'linear' : easingToLinear(parsed);
8174
8333
  }
8334
+ // Only cache string based easing name, otherwise function arguments get lost
8175
8335
  WAAPIEasesLookups[ease] = parsedEase;
8176
8336
  } else if (isFnc(ease)) {
8177
8337
  const easing = easingToLinear(ease);
@@ -8212,7 +8372,8 @@ let transformsPropertiesRegistered = null;
8212
8372
  * @return {String}
8213
8373
  */
8214
8374
  const normalizeTweenValue = (propName, value, $el, i, targetsLength) => {
8215
- let v = getFunctionValue(/** @type {any} */(value), $el, i, targetsLength);
8375
+ // Do not try to compute strings with getFunctionValue otherwise it will convert CSS variables
8376
+ let v = isStr(value) ? value : getFunctionValue(/** @type {any} */(value), $el, i, targetsLength);
8216
8377
  if (!isNum(v)) return v;
8217
8378
  if (commonDefaultPXProperties.includes(propName) || stringStartsWith(propName, 'translate')) return `${v}px`;
8218
8379
  if (stringStartsWith(propName, 'rotate') || stringStartsWith(propName, 'skew')) return `${v}deg`;
@@ -8292,7 +8453,7 @@ class WAAPIAnimation {
8292
8453
  /** @type {PlaybackDirection} */
8293
8454
  const direction = alternate ? reversed ? 'alternate-reverse' : 'alternate' : reversed ? 'reverse' : 'normal';
8294
8455
  /** @type {FillMode} */
8295
- const fill = 'forwards';
8456
+ const fill = 'both'; // We use 'both' here because the animation can be reversed during playback
8296
8457
  /** @type {String} */
8297
8458
  const easing = parseWAAPIEasing(ease);
8298
8459
  const timeScale = (globals.timeScale === 1 ? 1 : K);
@@ -8304,7 +8465,7 @@ class WAAPIAnimation {
8304
8465
  /** @type {globalThis.Animation}] */
8305
8466
  this.controlAnimation = null;
8306
8467
  /** @type {Callback<this>} */
8307
- this.onComplete = params.onComplete || noop;
8468
+ this.onComplete = params.onComplete || /** @type {Callback<WAAPIAnimation>} */(/** @type {unknown} */(globals.defaults.onComplete));
8308
8469
  /** @type {Number} */
8309
8470
  this.duration = 0;
8310
8471
  /** @type {Boolean} */
@@ -8315,6 +8476,8 @@ class WAAPIAnimation {
8315
8476
  this.paused = !autoplay || scroll !== false;
8316
8477
  /** @type {Boolean} */
8317
8478
  this.reversed = reversed;
8479
+ /** @type {Boolean} */
8480
+ this.persist = setValue(params.persist, globals.defaults.persist);
8318
8481
  /** @type {Boolean|ScrollObserver} */
8319
8482
  this.autoplay = autoplay;
8320
8483
  /** @type {Number} */
@@ -8323,17 +8486,18 @@ class WAAPIAnimation {
8323
8486
  this._resolve = noop; // Used by .then()
8324
8487
  /** @type {Number} */
8325
8488
  this._completed = 0;
8326
- /** @type {Array<Object>}] */
8327
- this._inlineStyles = parsedTargets.map($el => $el.getAttribute('style'));
8489
+ /** @type {Array.<Object>} */
8490
+ this._inlineStyles = [];
8328
8491
 
8329
8492
  parsedTargets.forEach(($el, i) => {
8330
8493
 
8331
8494
  const cachedTransforms = $el[transformsSymbol];
8332
-
8333
8495
  const hasIndividualTransforms = validIndividualTransforms.some(t => params.hasOwnProperty(t));
8496
+ const elStyle = $el.style;
8497
+ const inlineStyles = this._inlineStyles[i] = {};
8334
8498
 
8335
8499
  /** @type {Number} */
8336
- const duration = (spring ? /** @type {Spring} */(spring).duration : getFunctionValue(setValue(params.duration, globals.defaults.duration), $el, i, targetsLength)) * timeScale;
8500
+ const duration = (spring ? /** @type {Spring} */(spring).settlingDuration : getFunctionValue(setValue(params.duration, globals.defaults.duration), $el, i, targetsLength)) * timeScale;
8337
8501
  /** @type {Number} */
8338
8502
  const delay = getFunctionValue(setValue(params.delay, globals.defaults.delay), $el, i, targetsLength) * timeScale;
8339
8503
  /** @type {CompositeOperation} */
@@ -8347,6 +8511,12 @@ class WAAPIAnimation {
8347
8511
  const tweenParams = { iterations, direction, fill, easing, duration, delay, composite };
8348
8512
  const propertyValue = params[name];
8349
8513
  const individualTransformProperty = hasIndividualTransforms ? validTransforms.includes(name) ? name : shortTransforms.get(name) : false;
8514
+
8515
+ const styleName = individualTransformProperty ? 'transform' : name;
8516
+ if (!inlineStyles[styleName]) {
8517
+ inlineStyles[styleName] = elStyle[styleName];
8518
+ }
8519
+
8350
8520
  let parsedPropertyValue;
8351
8521
  if (isObj(propertyValue)) {
8352
8522
  const tweenOptions = /** @type {WAAPITweenOptions} */(propertyValue);
@@ -8355,7 +8525,7 @@ class WAAPIAnimation {
8355
8525
  const to = /** @type {WAAPITweenOptions} */(tweenOptions).to;
8356
8526
  const from = /** @type {WAAPITweenOptions} */(tweenOptions).from;
8357
8527
  /** @type {Number} */
8358
- tweenParams.duration = (tweenOptionsSpring ? /** @type {Spring} */(tweenOptionsSpring).duration : getFunctionValue(setValue(tweenOptions.duration, duration), $el, i, targetsLength)) * timeScale;
8528
+ tweenParams.duration = (tweenOptionsSpring ? /** @type {Spring} */(tweenOptionsSpring).settlingDuration : getFunctionValue(setValue(tweenOptions.duration, duration), $el, i, targetsLength)) * timeScale;
8359
8529
  /** @type {Number} */
8360
8530
  tweenParams.delay = getFunctionValue(setValue(tweenOptions.delay, delay), $el, i, targetsLength) * timeScale;
8361
8531
  /** @type {CompositeOperation} */
@@ -8372,10 +8542,10 @@ class WAAPIAnimation {
8372
8542
  addWAAPIAnimation(this, $el, name, keyframes, tweenParams);
8373
8543
  if (!isUnd(from)) {
8374
8544
  if (!individualTransformProperty) {
8375
- $el.style[name] = keyframes[name][0];
8545
+ elStyle[name] = keyframes[name][0];
8376
8546
  } else {
8377
8547
  const key = `--${individualTransformProperty}`;
8378
- $el.style.setProperty(key, keyframes[key][0]);
8548
+ elStyle.setProperty(key, keyframes[key][0]);
8379
8549
  }
8380
8550
  }
8381
8551
  } else {
@@ -8396,7 +8566,7 @@ class WAAPIAnimation {
8396
8566
  for (let t in cachedTransforms) {
8397
8567
  transforms += `${transformsFragmentStrings[t]}var(--${t})) `;
8398
8568
  }
8399
- $el.style.transform = transforms;
8569
+ elStyle.transform = transforms;
8400
8570
  }
8401
8571
  });
8402
8572
 
@@ -8441,7 +8611,8 @@ class WAAPIAnimation {
8441
8611
  // Make sure the animation playState is not 'paused' in order to properly trigger an onfinish callback.
8442
8612
  // The "paused" play state supersedes the "finished" play state; if the animation is both paused and finished, the "paused" state is the one that will be reported.
8443
8613
  // https://developer.mozilla.org/en-US/docs/Web/API/Animation/finish_event
8444
- if (t >= this.duration) anim.play();
8614
+ // This is not needed for persisting animations since they never finish.
8615
+ if (!this.persist && t >= this.duration) anim.play();
8445
8616
  anim.currentTime = t;
8446
8617
  });
8447
8618
  }
@@ -8511,13 +8682,30 @@ class WAAPIAnimation {
8511
8682
  }
8512
8683
 
8513
8684
  cancel() {
8514
- this.forEach('cancel');
8515
- return this.pause();
8685
+ this.muteCallbacks = true; // This prevents triggering the onComplete callback and resolving the Promise
8686
+ return this.commitStyles().forEach('cancel');
8516
8687
  }
8517
8688
 
8518
8689
  revert() {
8519
- this.cancel();
8520
- this.targets.forEach(($el, i) => $el.setAttribute('style', this._inlineStyles[i]) );
8690
+ // NOTE: We need a better way to revert the transforms, since right now the entire transform property value is reverted,
8691
+ // This means if you have multiple animations animating different transforms on the same target,
8692
+ // reverting one of them will also override the transform property of the other animations.
8693
+ // A better approach would be to store the original custom property values is they exist instead of the entire transform value,
8694
+ // and update the CSS variables with the orignal value
8695
+ this.cancel().targets.forEach(($el, i) => {
8696
+ const targetStyle = $el.style;
8697
+ const targetInlineStyles = this._inlineStyles[i];
8698
+ for (let name in targetInlineStyles) {
8699
+ const originalInlinedValue = targetInlineStyles[name];
8700
+ if (isUnd(originalInlinedValue) || originalInlinedValue === emptyString) {
8701
+ targetStyle.removeProperty(toLowerCase(name));
8702
+ } else {
8703
+ targetStyle[name] = originalInlinedValue;
8704
+ }
8705
+ }
8706
+ // Remove style attribute if empty
8707
+ if ($el.getAttribute('style') === emptyString) $el.removeAttribute('style');
8708
+ });
8521
8709
  return this;
8522
8710
  }
8523
8711
 
@@ -8551,4 +8739,4 @@ const waapi = {
8551
8739
  convertEase: easingToLinear
8552
8740
  };
8553
8741
 
8554
- export { registerTargets as $, Animatable, Draggable, JSAnimation, Scope, ScrollObserver, Spring, TextSplitter, Timeline, Timer, WAAPIAnimation, animate, clamp, cleanInlineStyles, createAnimatable, createDraggable, createDrawable, createMotionPath, createScope, createSeededRandom, createSpring, createTimeline, createTimer, cubicBezier, damp, degToRad, eases, index$3 as easings, engine, get, irregular, keepTime, lerp, linear, mapRange, morphTo, none, onScroll, padEnd, padStart, radToDeg, random, randomPick, remove, round, roundPad, scrollContainers, set, shuffle, snap, split, splitText, stagger, steps, index$1 as svg, sync, index as text, index$2 as utils, waapi, wrap };
8742
+ export { registerTargets as $, Animatable, Draggable, JSAnimation, Scope, ScrollObserver, Spring, TextSplitter, Timeline, Timer, WAAPIAnimation, animate, clamp, cleanInlineStyles, createAnimatable, createDraggable, createDrawable, createMotionPath, createScope, createSeededRandom, createSpring, createTimeline, createTimer, cubicBezier, damp, degToRad, eases, index$3 as easings, engine, get, irregular, keepTime, lerp, linear, mapRange, morphTo, onScroll, padEnd, padStart, radToDeg, random, randomPick, remove, round, roundPad, scrollContainers, set, shuffle, snap, split, splitText, spring, stagger, steps, index$1 as svg, sync, index as text, index$2 as utils, waapi, wrap };