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
@@ -688,6 +699,8 @@
688
699
  // Strings
689
700
 
690
701
  const emptyString = '';
702
+ const cssVarPrefix = 'var(';
703
+
691
704
  const shortTransforms = /*#__PURE__*/ (() => {
692
705
  const map = new Map();
693
706
  map.set('x', 'translateX');
@@ -711,9 +724,9 @@
711
724
  'skew',
712
725
  'skewX',
713
726
  'skewY',
714
- 'perspective',
715
727
  'matrix',
716
728
  'matrix3d',
729
+ 'perspective',
717
730
  ];
718
731
 
719
732
  const transformsFragmentStrings = /*#__PURE__*/ validTransforms.reduce((a, v) => ({...a, [v]: v + '('}), {});
@@ -737,6 +750,7 @@
737
750
  const lowerCaseRgx = /([a-z])([A-Z])/g;
738
751
  const transformsExecRgx = /(\w+)(\([^)]+\)+)/g; // Match inline transforms with cacl() values, returns the value wrapped in ()
739
752
  const relativeValuesExecRgx = /(\*=|\+=|-=)/;
753
+ const cssVariableMatchRgx = /var\(\s*(--[\w-]+)(?:\s*,\s*([^)]+))?\s*\)/;
740
754
 
741
755
 
742
756
 
@@ -751,6 +765,7 @@
751
765
  reversed: false,
752
766
  alternate: false,
753
767
  autoplay: true,
768
+ persist: false,
754
769
  duration: K,
755
770
  delay: 0,
756
771
  loopDelay: 0,
@@ -1174,19 +1189,30 @@
1174
1189
  * @return {any}
1175
1190
  */
1176
1191
  const getFunctionValue = (value, target, index, total, store) => {
1192
+ let func;
1177
1193
  if (isFnc(value)) {
1178
- const func = () => {
1194
+ func = () => {
1179
1195
  const computed = /** @type {Function} */(value)(target, index, total);
1180
1196
  // Fallback to 0 if the function returns undefined / NaN / null / false / 0
1181
1197
  return !isNaN(+computed) ? +computed : computed || 0;
1182
1198
  };
1183
- if (store) {
1184
- store.func = func;
1185
- }
1186
- return func();
1199
+ } else if (isStr(value) && stringStartsWith(value, cssVarPrefix)) {
1200
+ func = () => {
1201
+ const match = value.match(cssVariableMatchRgx);
1202
+ const cssVarName = match[1];
1203
+ const fallbackValue = match[2];
1204
+ let computed = getComputedStyle(/** @type {HTMLElement} */(target))?.getPropertyValue(cssVarName);
1205
+ // Use fallback if CSS variable is not set or empty
1206
+ if ((!computed || computed.trim() === emptyString) && fallbackValue) {
1207
+ computed = fallbackValue.trim();
1208
+ }
1209
+ return computed || 0;
1210
+ };
1187
1211
  } else {
1188
1212
  return value;
1189
1213
  }
1214
+ if (store) store.func = func;
1215
+ return func();
1190
1216
  };
1191
1217
 
1192
1218
  /**
@@ -1593,7 +1619,9 @@
1593
1619
  // Handle setters on timeline differently and allow re-trigering the onComplete callback when seeking backwards
1594
1620
  if (parent && isSetter) {
1595
1621
  if (!muteCallbacks && (
1596
- (parent.began && !isRunningBackwards && tickableAbsoluteTime >= duration && !completed) ||
1622
+ // (tickableAbsoluteTime > 0 instead) of (tickableAbsoluteTime >= duration) to prevent floating point precision issues
1623
+ // see: https://github.com/juliangarnier/anime/issues/1088
1624
+ (parent.began && !isRunningBackwards && tickableAbsoluteTime > 0 && !completed) ||
1597
1625
  (isRunningBackwards && tickableAbsoluteTime <= minValue && completed)
1598
1626
  )) {
1599
1627
  tickable.onComplete(/** @type {CallbackArgument} */(tickable));
@@ -1695,13 +1723,12 @@
1695
1723
  }
1696
1724
  };
1697
1725
 
1698
- const propertyNamesCache = {};
1699
-
1700
-
1701
1726
 
1702
1727
 
1703
1728
 
1704
1729
 
1730
+ const propertyNamesCache = {};
1731
+
1705
1732
  /**
1706
1733
  * @param {String} propertyName
1707
1734
  * @param {Target} target
@@ -1748,10 +1775,11 @@
1748
1775
  const tweenTarget = tween.target;
1749
1776
  if (tweenTarget[isDomSymbol]) {
1750
1777
  const targetStyle = /** @type {DOMTarget} */(tweenTarget).style;
1751
- const originalInlinedValue = animation._inlineStyles[tweenProperty];
1778
+ const originalInlinedValue = tween._inlineValue;
1779
+ const tweenHadNoInlineValue = isNil(originalInlinedValue) || originalInlinedValue === emptyString;
1752
1780
  if (tween._tweenType === tweenTypes.TRANSFORM) {
1753
1781
  const cachedTransforms = tweenTarget[transformsSymbol];
1754
- if (isUnd(originalInlinedValue) || originalInlinedValue === emptyString) {
1782
+ if (tweenHadNoInlineValue) {
1755
1783
  delete cachedTransforms[tweenProperty];
1756
1784
  } else {
1757
1785
  cachedTransforms[tweenProperty] = originalInlinedValue;
@@ -1768,8 +1796,8 @@
1768
1796
  }
1769
1797
  }
1770
1798
  } else {
1771
- if (isUnd(originalInlinedValue) || originalInlinedValue === emptyString) {
1772
- targetStyle.removeProperty(tweenProperty);
1799
+ if (tweenHadNoInlineValue) {
1800
+ targetStyle.removeProperty(toLowerCase(tweenProperty));
1773
1801
  } else {
1774
1802
  targetStyle[tweenProperty] = originalInlinedValue;
1775
1803
  }
@@ -3054,6 +3082,7 @@
3054
3082
 
3055
3083
 
3056
3084
 
3085
+
3057
3086
  /** @type {PowerEasing} */
3058
3087
  const easeInPower = (p = 1.68) => t => pow(t, +p);
3059
3088
 
@@ -3071,154 +3100,6 @@
3071
3100
  outIn: easeIn => t => t < .5 ? (1 - easeIn(1 - t * 2)) / 2 : (easeIn(t * 2 - 1) + 1) / 2,
3072
3101
  };
3073
3102
 
3074
- /**
3075
- * @param {String} string
3076
- * @param {Record<String, EasingFunctionWithParams|EasingFunction>} easesFunctions
3077
- * @param {Object} easesLookups
3078
- * @return {EasingFunction}
3079
- */
3080
- const parseEaseString = (string, easesFunctions, easesLookups) => {
3081
- if (easesLookups[string]) return easesLookups[string];
3082
- if (string.indexOf('(') <= -1) {
3083
- const hasParams = easeTypes[string] || string.includes('Back') || string.includes('Elastic');
3084
- const parsedFn = /** @type {EasingFunction} */(hasParams ? /** @type {EasingFunctionWithParams} */(easesFunctions[string])() : easesFunctions[string]);
3085
- return parsedFn ? easesLookups[string] = parsedFn : none;
3086
- } else {
3087
- const split = string.slice(0, -1).split('(');
3088
- const parsedFn = /** @type {EasingFunctionWithParams} */(easesFunctions[split[0]]);
3089
- return parsedFn ? easesLookups[string] = parsedFn(...split[1].split(',')) : none;
3090
- }
3091
- };
3092
-
3093
-
3094
-
3095
- /**
3096
- * Cubic Bezier solver adapted from https://github.com/gre/bezier-easing
3097
- * (c) 2014 Gaëtan Renaudeau
3098
- */
3099
-
3100
- /**
3101
- * @param {Number} aT
3102
- * @param {Number} aA1
3103
- * @param {Number} aA2
3104
- * @return {Number}
3105
- */
3106
- const calcBezier = (aT, aA1, aA2) => (((1 - 3 * aA2 + 3 * aA1) * aT + (3 * aA2 - 6 * aA1)) * aT + (3 * aA1)) * aT;
3107
-
3108
- /**
3109
- * @param {Number} aX
3110
- * @param {Number} mX1
3111
- * @param {Number} mX2
3112
- * @return {Number}
3113
- */
3114
- const binarySubdivide = (aX, mX1, mX2) => {
3115
- let aA = 0, aB = 1, currentX, currentT, i = 0;
3116
- do {
3117
- currentT = aA + (aB - aA) / 2;
3118
- currentX = calcBezier(currentT, mX1, mX2) - aX;
3119
- if (currentX > 0) {
3120
- aB = currentT;
3121
- } else {
3122
- aA = currentT;
3123
- }
3124
- } while (abs(currentX) > .0000001 && ++i < 100);
3125
- return currentT;
3126
- };
3127
-
3128
- /**
3129
- * @param {Number} [mX1] The x coordinate of the first point
3130
- * @param {Number} [mY1] The y coordinate of the first point
3131
- * @param {Number} [mX2] The x coordinate of the second point
3132
- * @param {Number} [mY2] The y coordinate of the second point
3133
- * @return {EasingFunction}
3134
- */
3135
-
3136
- const cubicBezier = (mX1 = 0.5, mY1 = 0.0, mX2 = 0.5, mY2 = 1.0) => (mX1 === mY1 && mX2 === mY2) ? none :
3137
- t => t === 0 || t === 1 ? t :
3138
- calcBezier(binarySubdivide(t, mX1, mX2), mY1, mY2);
3139
-
3140
-
3141
-
3142
- /**
3143
- * Steps ease implementation https://developer.mozilla.org/fr/docs/Web/CSS/transition-timing-function
3144
- * Only covers 'end' and 'start' jumpterms
3145
- * @param {Number} steps
3146
- * @param {Boolean} [fromStart]
3147
- * @return {EasingFunction}
3148
- */
3149
- const steps = (steps = 10, fromStart) => {
3150
- const roundMethod = fromStart ? ceil : floor;
3151
- return t => roundMethod(clamp$1(t, 0, 1) * steps) * (1 / steps);
3152
- };
3153
-
3154
-
3155
-
3156
- /**
3157
- * Without parameters, the linear function creates a non-eased transition.
3158
- * Parameters, if used, creates a piecewise linear easing by interpolating linearly between the specified points.
3159
- *
3160
- * @param {...(String|Number)} args - Points
3161
- * @return {EasingFunction}
3162
- */
3163
- const linear = (...args) => {
3164
- const argsLength = args.length;
3165
- if (!argsLength) return none;
3166
- const totalPoints = argsLength - 1;
3167
- const firstArg = args[0];
3168
- const lastArg = args[totalPoints];
3169
- const xPoints = [0];
3170
- const yPoints = [parseNumber(firstArg)];
3171
- for (let i = 1; i < totalPoints; i++) {
3172
- const arg = args[i];
3173
- const splitValue = isStr(arg) ?
3174
- /** @type {String} */(arg).trim().split(' ') :
3175
- [arg];
3176
- const value = splitValue[0];
3177
- const percent = splitValue[1];
3178
- xPoints.push(!isUnd(percent) ? parseNumber(percent) / 100 : i / totalPoints);
3179
- yPoints.push(parseNumber(value));
3180
- }
3181
- yPoints.push(parseNumber(lastArg));
3182
- xPoints.push(1);
3183
- return function easeLinear(t) {
3184
- for (let i = 1, l = xPoints.length; i < l; i++) {
3185
- const currentX = xPoints[i];
3186
- if (t <= currentX) {
3187
- const prevX = xPoints[i - 1];
3188
- const prevY = yPoints[i - 1];
3189
- return prevY + (yPoints[i] - prevY) * (t - prevX) / (currentX - prevX);
3190
- }
3191
- }
3192
- return yPoints[yPoints.length - 1];
3193
- }
3194
- };
3195
-
3196
-
3197
-
3198
- /**
3199
- * Generate random steps
3200
- * @param {Number} [length] - The number of steps
3201
- * @param {Number} [randomness] - How strong the randomness is
3202
- * @return {EasingFunction}
3203
- */
3204
- const irregular = (length = 10, randomness = 1) => {
3205
- const values = [0];
3206
- const total = length - 1;
3207
- for (let i = 1; i < total; i++) {
3208
- const previousValue = values[i - 1];
3209
- const spacing = i / total;
3210
- const segmentEnd = (i + 1) / total;
3211
- const randomVariation = spacing + (segmentEnd - spacing) * Math.random();
3212
- // Mix the even spacing and random variation based on the randomness parameter
3213
- const randomValue = spacing * (1 - randomness) + randomVariation * randomness;
3214
- values.push(clamp$1(randomValue, previousValue, 1));
3215
- }
3216
- values.push(1);
3217
- return linear(...values);
3218
- };
3219
-
3220
-
3221
-
3222
3103
  /**
3223
3104
  * Easing functions adapted and simplified from https://robertpenner.com/easing/
3224
3105
  * (c) 2001 Robert Penner
@@ -3247,7 +3128,7 @@
3247
3128
  return 1 / pow(4, 3 - b) - 7.5625 * pow((pow2 * 3 - 2) / 22 - t, 2);
3248
3129
  },
3249
3130
  /** @type {BackEasing} */
3250
- Back: (overshoot = 1.70158) => t => (+overshoot + 1) * t * t * t - +overshoot * t * t,
3131
+ Back: (overshoot = 1.7) => t => (+overshoot + 1) * t * t * t - +overshoot * t * t,
3251
3132
  /** @type {ElasticEasing} */
3252
3133
  Elastic: (amplitude = 1, period = .3) => {
3253
3134
  const a = clamp$1(+amplitude, 1, 10);
@@ -3260,10 +3141,8 @@
3260
3141
 
3261
3142
  /**
3262
3143
  * @typedef {Object} EasesFunctions
3263
- * @property {typeof linear} linear
3264
- * @property {typeof irregular} irregular
3265
- * @property {typeof steps} steps
3266
- * @property {typeof cubicBezier} cubicBezier
3144
+ * @property {typeof none} linear
3145
+ * @property {typeof none} none
3267
3146
  * @property {PowerEasing} in
3268
3147
  * @property {PowerEasing} out
3269
3148
  * @property {PowerEasing} inOut
@@ -3311,7 +3190,7 @@
3311
3190
  */
3312
3191
 
3313
3192
  const eases = (/*#__PURE__ */ (() => {
3314
- const list = { linear, irregular, steps, cubicBezier };
3193
+ const list = { linear: none, none: none };
3315
3194
  for (let type in easeTypes) {
3316
3195
  for (let name in easeInFunctions) {
3317
3196
  const easeIn = easeInFunctions[name];
@@ -3327,15 +3206,43 @@
3327
3206
  })());
3328
3207
 
3329
3208
  /** @type {Record<String, EasingFunction>} */
3330
- const JSEasesLookups = { linear: none };
3209
+ const easesLookups = { linear: none, none: none };
3210
+
3211
+ /**
3212
+ * @param {String} string
3213
+ * @return {EasingFunction}
3214
+ */
3215
+ const parseEaseString = (string) => {
3216
+ if (easesLookups[string]) return easesLookups[string];
3217
+ if (string.indexOf('(') <= -1) {
3218
+ const hasParams = easeTypes[string] || string.includes('Back') || string.includes('Elastic');
3219
+ const parsedFn = /** @type {EasingFunction} */(hasParams ? /** @type {EasingFunctionWithParams} */(eases[string])() : eases[string]);
3220
+ return parsedFn ? easesLookups[string] = parsedFn : none;
3221
+ } else {
3222
+ const split = string.slice(0, -1).split('(');
3223
+ const parsedFn = /** @type {EasingFunctionWithParams} */(eases[split[0]]);
3224
+ return parsedFn ? easesLookups[string] = parsedFn(...split[1].split(',')) : none;
3225
+ }
3226
+ };
3227
+
3228
+ const deprecated = ['steps(', 'irregular(', 'linear(', 'cubicBezier('];
3331
3229
 
3332
3230
  /**
3333
3231
  * @param {EasingParam} ease
3334
3232
  * @return {EasingFunction}
3335
3233
  */
3336
- const parseEase = ease => isFnc(ease) ? ease :
3337
- isStr(ease) ? parseEaseString(/** @type {String} */(ease), eases, JSEasesLookups) :
3338
- none;
3234
+ const parseEase = ease => {
3235
+ if (isStr(ease)) {
3236
+ for (let i = 0, l = deprecated.length; i < l; i++) {
3237
+ if (stringStartsWith(ease, deprecated[i])) {
3238
+ 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}\``);
3239
+ return none;
3240
+ }
3241
+ }
3242
+ }
3243
+ const easeFunc = isFnc(ease) ? ease : isStr(ease) ? parseEaseString(/** @type {String} */(ease)) : none;
3244
+ return easeFunc;
3245
+ };
3339
3246
 
3340
3247
 
3341
3248
 
@@ -3343,6 +3250,7 @@
3343
3250
  // TODO: Maybe move the objects creation to values.js and use the decompose function to create the base object
3344
3251
  const fromTargetObject = createDecomposedValueTargetObject();
3345
3252
  const toTargetObject = createDecomposedValueTargetObject();
3253
+ const inlineStylesStore = {};
3346
3254
  const toFunctionStore = { func: null };
3347
3255
  const keyframesTargetArray = [null];
3348
3256
  const fastSetValuesArray = [null, null];
@@ -3487,15 +3395,15 @@
3487
3395
  const animEase = animaPlaybackEase ? parseEase(animaPlaybackEase) : null;
3488
3396
  const hasSpring = !isUnd(ease) && !isUnd(/** @type {Spring} */(ease).ease);
3489
3397
  const tEasing = hasSpring ? /** @type {Spring} */(ease).ease : setValue(ease, animEase ? 'linear' : animDefaults.ease);
3490
- const tDuration = hasSpring ? /** @type {Spring} */(ease).duration : setValue(duration, animDefaults.duration);
3398
+ const tDuration = hasSpring ? /** @type {Spring} */(ease).settlingDuration : setValue(duration, animDefaults.duration);
3491
3399
  const tDelay = setValue(delay, animDefaults.delay);
3492
3400
  const tModifier = modifier || animDefaults.modifier;
3493
3401
  // If no composition is defined and the targets length is high (>= 1000) set the composition to 'none' (0) for faster tween creation
3494
3402
  const tComposition = isUnd(composition) && targetsLength >= K ? compositionTypes.none : !isUnd(composition) ? composition : animDefaults.composition;
3495
- // TODO: Do not create an empty object until we know the animation will generate inline styles
3496
- const animInlineStyles = {};
3497
3403
  // const absoluteOffsetTime = this._offset;
3498
3404
  const absoluteOffsetTime = this._offset + (parent ? parent._offset : 0);
3405
+ // This allows targeting the current animation in the spring onComplete callback
3406
+ if (hasSpring) /** @type {Spring} */(ease).parent = this;
3499
3407
 
3500
3408
  let iterationDuration = NaN;
3501
3409
  let iterationDelay = NaN;
@@ -3597,7 +3505,7 @@
3597
3505
  // 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
3598
3506
  const tweenEasing = hasSpring ? /** @type {Spring} */(keyEasing).ease : keyEasing || tEasing;
3599
3507
  // Calculate default individual keyframe duration by dividing the tl of keyframes
3600
- const tweenDuration = hasSpring ? /** @type {Spring} */(keyEasing).duration : getFunctionValue(setValue(key.duration, (l > 1 ? getFunctionValue(tDuration, target, ti, tl) / l : tDuration)), target, ti, tl);
3508
+ const tweenDuration = hasSpring ? /** @type {Spring} */(keyEasing).settlingDuration : getFunctionValue(setValue(key.duration, (l > 1 ? getFunctionValue(tDuration, target, ti, tl) / l : tDuration)), target, ti, tl);
3601
3509
  // Default delay value should only be applied to the first tween
3602
3510
  const tweenDelay = getFunctionValue(setValue(key.delay, (!tweenIndex ? tDelay : 0)), target, ti, tl);
3603
3511
  const computedComposition = getFunctionValue(setValue(key.composition, tComposition), target, ti, tl);
@@ -3647,7 +3555,7 @@
3647
3555
  }
3648
3556
  } else {
3649
3557
  decomposeRawValue(
3650
- getOriginalAnimatableValue(target, propName, tweenType, animInlineStyles),
3558
+ getOriginalAnimatableValue(target, propName, tweenType, inlineStylesStore),
3651
3559
  decomposedOriginalValue
3652
3560
  );
3653
3561
  if (decomposedOriginalValue.t === valueTypes.UNIT) {
@@ -3665,7 +3573,7 @@
3665
3573
  } else {
3666
3574
  // 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
3667
3575
  decomposeRawValue(parent && prevSibling && prevSibling.parent.parent === parent ? prevSibling._value :
3668
- getOriginalAnimatableValue(target, propName, tweenType, animInlineStyles), toTargetObject);
3576
+ getOriginalAnimatableValue(target, propName, tweenType, inlineStylesStore), toTargetObject);
3669
3577
  }
3670
3578
  }
3671
3579
  if (hasFromvalue) {
@@ -3676,7 +3584,7 @@
3676
3584
  } else {
3677
3585
  decomposeRawValue(parent && prevSibling && prevSibling.parent.parent === parent ? prevSibling._value :
3678
3586
  // 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
3679
- getOriginalAnimatableValue(target, propName, tweenType, animInlineStyles), fromTargetObject);
3587
+ getOriginalAnimatableValue(target, propName, tweenType, inlineStylesStore), fromTargetObject);
3680
3588
  }
3681
3589
  }
3682
3590
  }
@@ -3685,7 +3593,7 @@
3685
3593
  if (fromTargetObject.o) {
3686
3594
  fromTargetObject.n = getRelativeValue(
3687
3595
  !prevSibling ? decomposeRawValue(
3688
- getOriginalAnimatableValue(target, propName, tweenType, animInlineStyles),
3596
+ getOriginalAnimatableValue(target, propName, tweenType, inlineStylesStore),
3689
3597
  decomposedOriginalValue
3690
3598
  ).n : prevSibling._toNumber,
3691
3599
  fromTargetObject.n,
@@ -3741,6 +3649,10 @@
3741
3649
  // Rounding is necessary here to minimize floating point errors when working in seconds
3742
3650
  const tweenUpdateDuration = round$1(+tweenDuration || minValue, 12);
3743
3651
 
3652
+ // Copy the value of the iniline style if it exist and imediatly nullify it to prevents false positive on other targets
3653
+ let inlineValue = inlineStylesStore[propName];
3654
+ if (!isNil(inlineValue)) inlineStylesStore[propName] = null;
3655
+
3744
3656
  /** @type {Tween} */
3745
3657
  const tween = {
3746
3658
  parent: this,
@@ -3772,6 +3684,7 @@
3772
3684
  _isOverlapped: 0,
3773
3685
  _isOverridden: 0,
3774
3686
  _renderTransforms: 0,
3687
+ _inlineValue: inlineValue,
3775
3688
  _prevRep: null, // For replaced tween
3776
3689
  _nextRep: null, // For replaced tween
3777
3690
  _prevAdd: null, // For additive tween
@@ -3874,8 +3787,6 @@
3874
3787
  // this._offset += parent ? iterationDelay : 0;
3875
3788
  /** @type {Number} */
3876
3789
  this.iterationDuration = iterationDuration;
3877
- /** @type {{}} */
3878
- this._inlineStyles = animInlineStyles;
3879
3790
 
3880
3791
  if (!this._autoplay && shouldTriggerRender) this.onRender(this);
3881
3792
  }
@@ -3909,6 +3820,7 @@
3909
3820
  if (tweenFunc) {
3910
3821
  const ogValue = getOriginalAnimatableValue(tween.target, tween.property, tween._tweenType);
3911
3822
  decomposeRawValue(ogValue, decomposedOriginalValue);
3823
+ // TODO: Check for from / to Array based values here,
3912
3824
  decomposeRawValue(tweenFunc(), toTargetObject);
3913
3825
  tween._fromNumbers = cloneArray(decomposedOriginalValue.d);
3914
3826
  tween._fromNumber = decomposedOriginalValue.n;
@@ -3918,6 +3830,8 @@
3918
3830
  tween._toNumber = toTargetObject.o ? getRelativeValue(decomposedOriginalValue.n, toTargetObject.n, toTargetObject.o) : toTargetObject.n;
3919
3831
  }
3920
3832
  });
3833
+ // This forces setter animations to render once
3834
+ if (this.duration === minValue) this.restart();
3921
3835
  return this;
3922
3836
  }
3923
3837
 
@@ -3960,16 +3874,18 @@
3960
3874
  * @param {DOMTarget} $el
3961
3875
  * @param {String} [property]
3962
3876
  * @param {WAAPIAnimation} [parent]
3877
+ * @return {globalThis.Animation}
3963
3878
  */
3964
3879
  const removeWAAPIAnimation = ($el, property, parent) => {
3965
3880
  let nextLookup = WAAPIAnimationsLookups._head;
3881
+ let anim;
3966
3882
  while (nextLookup) {
3967
3883
  const next = nextLookup._next;
3968
3884
  const matchTarget = nextLookup.$el === $el;
3969
3885
  const matchProperty = !property || nextLookup.property === property;
3970
3886
  const matchParent = !parent || nextLookup.parent === parent;
3971
3887
  if (matchTarget && matchProperty && matchParent) {
3972
- const anim = nextLookup.animation;
3888
+ anim = nextLookup.animation;
3973
3889
  try { anim.commitStyles(); } catch {} anim.cancel();
3974
3890
  removeChild(WAAPIAnimationsLookups, nextLookup);
3975
3891
  const lookupParent = nextLookup.parent;
@@ -3977,8 +3893,8 @@
3977
3893
  lookupParent._completed++;
3978
3894
  if (lookupParent.animations.length === lookupParent._completed) {
3979
3895
  lookupParent.completed = true;
3896
+ lookupParent.paused = true;
3980
3897
  if (!lookupParent.muteCallbacks) {
3981
- lookupParent.paused = true;
3982
3898
  lookupParent.onComplete(lookupParent);
3983
3899
  lookupParent._resolve(lookupParent);
3984
3900
  }
@@ -3987,6 +3903,7 @@
3987
3903
  }
3988
3904
  nextLookup = next;
3989
3905
  }
3906
+ return anim;
3990
3907
  };
3991
3908
 
3992
3909
  /**
@@ -3995,7 +3912,7 @@
3995
3912
  * @param {String} property
3996
3913
  * @param {PropertyIndexedKeyframes} keyframes
3997
3914
  * @param {KeyframeAnimationOptions} params
3998
- * @retun {Animation}
3915
+ * @retun {globalThis.Animation}
3999
3916
  */
4000
3917
  const addWAAPIAnimation = (parent, $el, property, keyframes, params) => {
4001
3918
  const animation = $el.animate(keyframes, params);
@@ -4010,8 +3927,11 @@
4010
3927
  removeWAAPIAnimation($el, property);
4011
3928
  addChild(WAAPIAnimationsLookups, { parent, animation, $el, property, _next: null, _prev: null });
4012
3929
  const handleRemove = () => { removeWAAPIAnimation($el, property, parent); };
3930
+ animation.oncancel = handleRemove;
4013
3931
  animation.onremove = handleRemove;
4014
- animation.onfinish = handleRemove;
3932
+ if (!parent.persist) {
3933
+ animation.onfinish = handleRemove;
3934
+ }
4015
3935
  return animation;
4016
3936
  };
4017
3937
 
@@ -4639,8 +4559,10 @@
4639
4559
 
4640
4560
 
4641
4561
 
4562
+
4563
+
4642
4564
  /*
4643
- * Spring ease solver adapted from https://webkit.org/demos/spring/spring.js
4565
+ * Spring easing solver adapted from https://webkit.org/demos/spring/spring.js
4644
4566
  * (c) 2016 Webkit - Apple Inc
4645
4567
  */
4646
4568
 
@@ -4651,25 +4573,46 @@
4651
4573
  * @param {SpringParams} [parameters]
4652
4574
  */
4653
4575
  constructor(parameters = {}) {
4576
+ const hasBounceOrDuration = !isUnd(parameters.bounce) || !isUnd(parameters.duration);
4654
4577
  this.timeStep = .02; // Interval fed to the solver to calculate duration
4655
4578
  this.restThreshold = .0005; // Values below this threshold are considered resting position
4656
4579
  this.restDuration = 200; // Duration in ms used to check if the spring is resting after reaching restThreshold
4657
4580
  this.maxDuration = 60000; // The maximum allowed spring duration in ms (default 1 min)
4658
4581
  this.maxRestSteps = this.restDuration / this.timeStep / K; // How many steps allowed after reaching restThreshold before stopping the duration calculation
4659
4582
  this.maxIterations = this.maxDuration / this.timeStep / K; // Calculate the maximum iterations allowed based on maxDuration
4660
- this.m = clamp$1(setValue(parameters.mass, 1), 0, maxSpringParamValue);
4661
- this.s = clamp$1(setValue(parameters.stiffness, 100), 1, maxSpringParamValue);
4662
- this.d = clamp$1(setValue(parameters.damping, 10), .1, maxSpringParamValue);
4583
+ this.bn = clamp$1(setValue(parameters.bounce, .5), -1, 1); // The bounce percentage between -1 and 1.
4584
+ this.pd = clamp$1(setValue(parameters.duration, 628), 10 * globals.timeScale, maxSpringParamValue * globals.timeScale); // The perceived duration
4585
+ this.m = clamp$1(setValue(parameters.mass, 1), 1, maxSpringParamValue);
4586
+ this.s = clamp$1(setValue(parameters.stiffness, 100), minValue, maxSpringParamValue);
4587
+ this.d = clamp$1(setValue(parameters.damping, 10), minValue, maxSpringParamValue);
4663
4588
  this.v = clamp$1(setValue(parameters.velocity, 0), -maxSpringParamValue, maxSpringParamValue);
4664
4589
  this.w0 = 0;
4665
4590
  this.zeta = 0;
4666
4591
  this.wd = 0;
4667
4592
  this.b = 0;
4593
+ this.completed = false;
4668
4594
  this.solverDuration = 0;
4669
- this.duration = 0;
4595
+ this.settlingDuration = 0;
4596
+ /** @type {JSAnimation} */
4597
+ this.parent = null;
4598
+ /** @type {Callback<JSAnimation>} */
4599
+ this.onComplete = parameters.onComplete || noop;
4600
+ if (hasBounceOrDuration) this.calculateSDFromBD();
4670
4601
  this.compute();
4671
4602
  /** @type {EasingFunction} */
4672
- this.ease = t => t === 0 || t === 1 ? t : this.solve(t * this.solverDuration);
4603
+ this.ease = t => {
4604
+ const currentTime = t * this.settlingDuration;
4605
+ const completed = this.completed;
4606
+ const perceivedTime = this.pd;
4607
+ if (currentTime >= perceivedTime && !completed) {
4608
+ this.completed = true;
4609
+ this.onComplete(this.parent);
4610
+ }
4611
+ if (currentTime < perceivedTime && completed) {
4612
+ this.completed = false;
4613
+ }
4614
+ return t === 0 || t === 1 ? t : this.solve(t * this.solverDuration);
4615
+ };
4673
4616
  }
4674
4617
 
4675
4618
  /** @type {EasingFunction} */
@@ -4677,23 +4620,83 @@
4677
4620
  const { zeta, w0, wd, b } = this;
4678
4621
  let t = time;
4679
4622
  if (zeta < 1) {
4623
+ // Underdamped
4680
4624
  t = exp(-t * zeta * w0) * (1 * cos(wd * t) + b * sin(wd * t));
4681
- } else {
4625
+ } else if (zeta === 1) {
4626
+ // Critically damped
4682
4627
  t = (1 + b * t) * exp(-t * w0);
4628
+ } else {
4629
+ // Overdamped
4630
+ // Using exponential instead of cosh and sinh functions to prevent Infinity
4631
+ // Original exp(-zeta * w0 * t) * (cosh(wd * t) + b * sinh(wd * t))
4632
+ t = ((1 + b) * exp((-zeta * w0 + wd) * t) + (1 - b) * exp((-zeta * w0 - wd) * t)) / 2;
4683
4633
  }
4684
4634
  return 1 - t;
4685
4635
  }
4686
4636
 
4637
+ calculateSDFromBD() {
4638
+ // Apple's SwiftUI perceived spring duration implementation https://developer.apple.com/videos/play/wwdc2023/10158/?time=1010
4639
+ // Equations taken from Kevin Grajeda's article https://www.kvin.me/posts/effortless-ui-spring-animations
4640
+ const pds = globals.timeScale === 1 ? this.pd / K : this.pd;
4641
+ // Mass and velocity should be set to their default values
4642
+ this.m = 1;
4643
+ this.v = 0;
4644
+ // Stiffness = (2π ÷ perceptualDuration)²
4645
+ this.s = pow((2 * PI) / pds, 2);
4646
+ if (this.bn >= 0) {
4647
+ // For bounce ≥ 0 (critically damped to underdamped)
4648
+ // damping = ((1 - bounce) × 4π) ÷ perceptualDuration
4649
+ this.d = ((1 - this.bn) * 4 * PI) / pds;
4650
+ } else {
4651
+ // For bounce < 0 (overdamped)
4652
+ // damping = 4π ÷ (perceptualDuration × (1 + bounce))
4653
+ // Note: (1 + bounce) is positive since bounce is negative
4654
+ this.d = (4 * PI) / (pds * (1 + this.bn));
4655
+ }
4656
+ this.s = round$1(clamp$1(this.s, minValue, maxSpringParamValue), 3);
4657
+ this.d = round$1(clamp$1(this.d, minValue, 300), 3); // Clamping to 300 is needed to prevent insane values in the solver
4658
+ }
4659
+
4660
+ calculateBDFromSD() {
4661
+ // Calculate perceived duration and bounce from stiffness and damping
4662
+ // Note: We assumes m = 1 and v = 0 for these calculations
4663
+ const pds = (2 * PI) / sqrt(this.s);
4664
+ this.pd = pds * (globals.timeScale === 1 ? K : 1);
4665
+ const zeta = this.d / (2 * sqrt(this.s));
4666
+ if (zeta <= 1) {
4667
+ // Critically damped to underdamped
4668
+ this.bn = 1 - (this.d * pds) / (4 * PI);
4669
+ } else {
4670
+ // Overdamped
4671
+ this.bn = (4 * PI) / (this.d * pds) - 1;
4672
+ }
4673
+ this.bn = round$1(clamp$1(this.bn, -1, 1), 3);
4674
+ this.pd = round$1(clamp$1(this.pd, 10 * globals.timeScale, maxSpringParamValue * globals.timeScale), 3);
4675
+ }
4676
+
4687
4677
  compute() {
4688
4678
  const { maxRestSteps, maxIterations, restThreshold, timeStep, m, d, s, v } = this;
4689
4679
  const w0 = this.w0 = clamp$1(sqrt(s / m), minValue, K);
4690
- const zeta = this.zeta = d / (2 * sqrt(s * m));
4691
- const wd = this.wd = zeta < 1 ? w0 * sqrt(1 - zeta * zeta) : 0;
4692
- this.b = zeta < 1 ? (zeta * w0 + -v) / wd : -v + w0;
4680
+ const bouncedZeta = this.zeta = d / (2 * sqrt(s * m));
4681
+ // Calculate wd based on damping type
4682
+ if (bouncedZeta < 1) {
4683
+ // Underdamped
4684
+ this.wd = w0 * sqrt(1 - bouncedZeta * bouncedZeta);
4685
+ this.b = (bouncedZeta * w0 + -v) / this.wd;
4686
+ } else if (bouncedZeta === 1) {
4687
+ // Critically damped
4688
+ this.wd = 0;
4689
+ this.b = -v + w0;
4690
+ } else {
4691
+ // Overdamped
4692
+ this.wd = w0 * sqrt(bouncedZeta * bouncedZeta - 1);
4693
+ this.b = (bouncedZeta * w0 + -v) / this.wd;
4694
+ }
4695
+
4693
4696
  let solverTime = 0;
4694
4697
  let restSteps = 0;
4695
4698
  let iterations = 0;
4696
- while (restSteps < maxRestSteps && iterations < maxIterations) {
4699
+ while (restSteps <= maxRestSteps && iterations <= maxIterations) {
4697
4700
  if (abs(1 - this.solve(solverTime)) < restThreshold) {
4698
4701
  restSteps++;
4699
4702
  } else {
@@ -4703,15 +4706,26 @@
4703
4706
  solverTime += timeStep;
4704
4707
  iterations++;
4705
4708
  }
4706
- this.duration = round$1(this.solverDuration * K, 0) * globals.timeScale;
4709
+ this.settlingDuration = round$1(this.solverDuration * K, 0) * globals.timeScale;
4707
4710
  }
4708
4711
 
4709
- get mass() {
4710
- return this.m;
4712
+ get bounce() {
4713
+ return this.bn;
4711
4714
  }
4712
4715
 
4713
- set mass(v) {
4714
- this.m = clamp$1(setValue(v, 1), 0, maxSpringParamValue);
4716
+ set bounce(v) {
4717
+ this.bn = clamp$1(setValue(v, 1), -1, 1);
4718
+ this.calculateSDFromBD();
4719
+ this.compute();
4720
+ }
4721
+
4722
+ get duration() {
4723
+ return this.pd;
4724
+ }
4725
+
4726
+ set duration(v) {
4727
+ this.pd = clamp$1(setValue(v, 1), 10 * globals.timeScale, maxSpringParamValue * globals.timeScale);
4728
+ this.calculateSDFromBD();
4715
4729
  this.compute();
4716
4730
  }
4717
4731
 
@@ -4720,7 +4734,8 @@
4720
4734
  }
4721
4735
 
4722
4736
  set stiffness(v) {
4723
- this.s = clamp$1(setValue(v, 100), 1, maxSpringParamValue);
4737
+ this.s = clamp$1(setValue(v, 100), minValue, maxSpringParamValue);
4738
+ this.calculateBDFromSD();
4724
4739
  this.compute();
4725
4740
  }
4726
4741
 
@@ -4729,7 +4744,17 @@
4729
4744
  }
4730
4745
 
4731
4746
  set damping(v) {
4732
- this.d = clamp$1(setValue(v, 10), .1, maxSpringParamValue);
4747
+ this.d = clamp$1(setValue(v, 10), minValue, maxSpringParamValue);
4748
+ this.calculateBDFromSD();
4749
+ this.compute();
4750
+ }
4751
+
4752
+ get mass() {
4753
+ return this.m;
4754
+ }
4755
+
4756
+ set mass(v) {
4757
+ this.m = clamp$1(setValue(v, 1), 1, maxSpringParamValue);
4733
4758
  this.compute();
4734
4759
  }
4735
4760
 
@@ -4747,7 +4772,18 @@
4747
4772
  * @param {SpringParams} [parameters]
4748
4773
  * @returns {Spring}
4749
4774
  */
4750
- const createSpring = (parameters) => new Spring(parameters);
4775
+ const spring = (parameters) => new Spring(parameters);
4776
+
4777
+ /**
4778
+ * @deprecated createSpring() is deprecated use spring() instead
4779
+ *
4780
+ * @param {SpringParams} [parameters]
4781
+ * @returns {Spring}
4782
+ */
4783
+ const createSpring = (parameters) => {
4784
+ console.warn('createSpring() is deprecated use spring() instead');
4785
+ return new Spring(parameters);
4786
+ };
4751
4787
 
4752
4788
 
4753
4789
 
@@ -4928,13 +4964,13 @@
4928
4964
  /** @type {Boolean|DraggableCursorParams} */
4929
4965
  this.cursor = false;
4930
4966
  /** @type {Spring} */
4931
- this.releaseXSpring = hasSpring ? /** @type {Spring} */(ease) : createSpring({
4967
+ this.releaseXSpring = 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),
4935
4971
  });
4936
4972
  /** @type {Spring} */
4937
- this.releaseYSpring = hasSpring ? /** @type {Spring} */(ease) : createSpring({
4973
+ this.releaseYSpring = hasSpring ? /** @type {Spring} */(ease) : spring({
4938
4974
  mass: setValue(parameters.releaseMass, 1),
4939
4975
  stiffness: setValue(parameters.releaseStiffness, 80),
4940
4976
  damping: setValue(parameters.releaseDamping, 20),
@@ -5651,8 +5687,8 @@
5651
5687
  this.$trigger.addEventListener('touchmove', preventDefault, { passive: false });
5652
5688
  this.$trigger.addEventListener('touchend', preventDefault);
5653
5689
 
5654
-
5655
- if ((!this.disabled[0] && abs(movedX) > 3) || (!this.disabled[1] && abs(movedY) > 3)) {
5690
+ // Don't check for a miminim distance move if already dragging
5691
+ if (this.dragged || (!this.disabled[0] && abs(movedX) > 3) || (!this.disabled[1] && abs(movedY) > 3)) {
5656
5692
 
5657
5693
  this.updateTicker.resume();
5658
5694
  this.pointer[2] = this.pointer[0];
@@ -5718,8 +5754,8 @@
5718
5754
  const directionX = dx === cr ? cx > cr ? -1 : 1 : cx < cl ? -1 : 1;
5719
5755
  const distanceX = round$1(cx - dx, 0);
5720
5756
  springX.velocity = disabledY && hasReleaseSpring ? distanceX ? (ds * directionX) / abs(distanceX) : 0 : pv;
5721
- const { ease, duration, restDuration } = springX;
5722
- durationX = cx === dx ? 0 : hasReleaseSpring ? duration : duration - (restDuration * globals.timeScale);
5757
+ const { ease, settlingDuration, restDuration } = springX;
5758
+ durationX = cx === dx ? 0 : hasReleaseSpring ? settlingDuration : settlingDuration - (restDuration * globals.timeScale);
5723
5759
  if (hasReleaseSpring) easeX = ease;
5724
5760
  if (durationX > longestReleaseDuration) longestReleaseDuration = durationX;
5725
5761
  }
@@ -5728,8 +5764,8 @@
5728
5764
  const directionY = dy === cb ? cy > cb ? -1 : 1 : cy < ct ? -1 : 1;
5729
5765
  const distanceY = round$1(cy - dy, 0);
5730
5766
  springY.velocity = disabledX && hasReleaseSpring ? distanceY ? (ds * directionY) / abs(distanceY) : 0 : pv;
5731
- const { ease, duration, restDuration } = springY;
5732
- durationY = cy === dy ? 0 : hasReleaseSpring ? duration : duration - (restDuration * globals.timeScale);
5767
+ const { ease, settlingDuration, restDuration } = springY;
5768
+ durationY = cy === dy ? 0 : hasReleaseSpring ? settlingDuration : settlingDuration - (restDuration * globals.timeScale);
5733
5769
  if (hasReleaseSpring) easeY = ease;
5734
5770
  if (durationY > longestReleaseDuration) longestReleaseDuration = durationY;
5735
5771
  }
@@ -6582,6 +6618,8 @@
6582
6618
  /** @type {Boolean} */
6583
6619
  this.reverted = false;
6584
6620
  /** @type {Boolean} */
6621
+ this.ready = false;
6622
+ /** @type {Boolean} */
6585
6623
  this.completed = false;
6586
6624
  /** @type {Boolean} */
6587
6625
  this.began = false;
@@ -6591,8 +6629,6 @@
6591
6629
  this.forceEnter = false;
6592
6630
  /** @type {Boolean} */
6593
6631
  this.hasEntered = false;
6594
- // /** @type {Array.<Number>} */
6595
- // this.offsets = [];
6596
6632
  /** @type {Number} */
6597
6633
  this.offset = 0;
6598
6634
  /** @type {Number} */
@@ -6640,6 +6676,8 @@
6640
6676
  // Make sure to pause the linked object in case it's added later
6641
6677
  linked.pause();
6642
6678
  this.linked = linked;
6679
+ // Forces WAAPI Animation to persist; otherwise, they will stop syncing on finish.
6680
+ if (!isUnd(/** @type {WAAPIAnimation} */(linked))) /** @type {WAAPIAnimation} */(linked).persist = true;
6643
6681
  // Try to use a target of the linked object if no target parameters specified
6644
6682
  if (!this._params.target) {
6645
6683
  /** @type {HTMLElement} */
@@ -6679,6 +6717,8 @@
6679
6717
  }
6680
6718
 
6681
6719
  refresh() {
6720
+ // This flag is used to prevent running handleScroll() outside of this.refresh() with values not yet calculated
6721
+ this.ready = true;
6682
6722
  this.reverted = false;
6683
6723
  const params = this._params;
6684
6724
  this.repeat = setValue(parseScrollObserverFunctionParameter(params.repeat, this), true);
@@ -6924,8 +6964,6 @@
6924
6964
  const offsetStart = parsedEnterTarget + offset - parsedEnterContainer;
6925
6965
  const offsetEnd = parsedLeaveTarget + offset - parsedLeaveContainer;
6926
6966
  const scrollDelta = offsetEnd - offsetStart;
6927
- // this.offsets[0] = offsetX;
6928
- // this.offsets[1] = offsetY;
6929
6967
  this.offset = offset;
6930
6968
  this.offsetStart = offsetStart;
6931
6969
  this.offsetEnd = offsetEnd;
@@ -6944,6 +6982,7 @@
6944
6982
  }
6945
6983
 
6946
6984
  handleScroll() {
6985
+ if (!this.ready) return;
6947
6986
  const linked = this.linked;
6948
6987
  const sync = this.sync;
6949
6988
  const syncEase = this.syncEase;
@@ -7067,6 +7106,7 @@
7067
7106
  this.removeDebug();
7068
7107
  }
7069
7108
  this.reverted = true;
7109
+ this.ready = false;
7070
7110
  return this;
7071
7111
  }
7072
7112
 
@@ -7078,13 +7118,142 @@
7078
7118
  */
7079
7119
  const onScroll = (parameters = {}) => new ScrollObserver(parameters);
7080
7120
 
7121
+
7122
+
7123
+ /**
7124
+ * Cubic Bezier solver adapted from https://github.com/gre/bezier-easing
7125
+ * (c) 2014 Gaëtan Renaudeau
7126
+ */
7127
+
7128
+ /**
7129
+ * @param {Number} aT
7130
+ * @param {Number} aA1
7131
+ * @param {Number} aA2
7132
+ * @return {Number}
7133
+ */
7134
+ const calcBezier = (aT, aA1, aA2) => (((1 - 3 * aA2 + 3 * aA1) * aT + (3 * aA2 - 6 * aA1)) * aT + (3 * aA1)) * aT;
7135
+
7136
+ /**
7137
+ * @param {Number} aX
7138
+ * @param {Number} mX1
7139
+ * @param {Number} mX2
7140
+ * @return {Number}
7141
+ */
7142
+ const binarySubdivide = (aX, mX1, mX2) => {
7143
+ let aA = 0, aB = 1, currentX, currentT, i = 0;
7144
+ do {
7145
+ currentT = aA + (aB - aA) / 2;
7146
+ currentX = calcBezier(currentT, mX1, mX2) - aX;
7147
+ if (currentX > 0) {
7148
+ aB = currentT;
7149
+ } else {
7150
+ aA = currentT;
7151
+ }
7152
+ } while (abs(currentX) > .0000001 && ++i < 100);
7153
+ return currentT;
7154
+ };
7155
+
7156
+ /**
7157
+ * @param {Number} [mX1] The x coordinate of the first point
7158
+ * @param {Number} [mY1] The y coordinate of the first point
7159
+ * @param {Number} [mX2] The x coordinate of the second point
7160
+ * @param {Number} [mY2] The y coordinate of the second point
7161
+ * @return {EasingFunction}
7162
+ */
7163
+
7164
+ const cubicBezier = (mX1 = 0.5, mY1 = 0.0, mX2 = 0.5, mY2 = 1.0) => (mX1 === mY1 && mX2 === mY2) ? none :
7165
+ t => t === 0 || t === 1 ? t :
7166
+ calcBezier(binarySubdivide(t, mX1, mX2), mY1, mY2);
7167
+
7168
+
7169
+
7170
+ /**
7171
+ * Steps ease implementation https://developer.mozilla.org/fr/docs/Web/CSS/transition-timing-function
7172
+ * Only covers 'end' and 'start' jumpterms
7173
+ * @param {Number} steps
7174
+ * @param {Boolean} [fromStart]
7175
+ * @return {EasingFunction}
7176
+ */
7177
+ const steps = (steps = 10, fromStart) => {
7178
+ const roundMethod = fromStart ? ceil : floor;
7179
+ return t => roundMethod(clamp$1(t, 0, 1) * steps) * (1 / steps);
7180
+ };
7181
+
7182
+
7183
+
7184
+ /**
7185
+ * Without parameters, the linear function creates a non-eased transition.
7186
+ * Parameters, if used, creates a piecewise linear easing by interpolating linearly between the specified points.
7187
+ *
7188
+ * @param {...(String|Number)} args - Points
7189
+ * @return {EasingFunction}
7190
+ */
7191
+ const linear = (...args) => {
7192
+ const argsLength = args.length;
7193
+ if (!argsLength) return none;
7194
+ const totalPoints = argsLength - 1;
7195
+ const firstArg = args[0];
7196
+ const lastArg = args[totalPoints];
7197
+ const xPoints = [0];
7198
+ const yPoints = [parseNumber(firstArg)];
7199
+ for (let i = 1; i < totalPoints; i++) {
7200
+ const arg = args[i];
7201
+ const splitValue = isStr(arg) ?
7202
+ /** @type {String} */(arg).trim().split(' ') :
7203
+ [arg];
7204
+ const value = splitValue[0];
7205
+ const percent = splitValue[1];
7206
+ xPoints.push(!isUnd(percent) ? parseNumber(percent) / 100 : i / totalPoints);
7207
+ yPoints.push(parseNumber(value));
7208
+ }
7209
+ yPoints.push(parseNumber(lastArg));
7210
+ xPoints.push(1);
7211
+ return function easeLinear(t) {
7212
+ for (let i = 1, l = xPoints.length; i < l; i++) {
7213
+ const currentX = xPoints[i];
7214
+ if (t <= currentX) {
7215
+ const prevX = xPoints[i - 1];
7216
+ const prevY = yPoints[i - 1];
7217
+ return prevY + (yPoints[i] - prevY) * (t - prevX) / (currentX - prevX);
7218
+ }
7219
+ }
7220
+ return yPoints[yPoints.length - 1];
7221
+ }
7222
+ };
7223
+
7224
+
7225
+
7226
+ /**
7227
+ * Generate random steps
7228
+ * @param {Number} [length] - The number of steps
7229
+ * @param {Number} [randomness] - How strong the randomness is
7230
+ * @return {EasingFunction}
7231
+ */
7232
+ const irregular = (length = 10, randomness = 1) => {
7233
+ const values = [0];
7234
+ const total = length - 1;
7235
+ for (let i = 1; i < total; i++) {
7236
+ const previousValue = values[i - 1];
7237
+ const spacing = i / total;
7238
+ const segmentEnd = (i + 1) / total;
7239
+ const randomVariation = spacing + (segmentEnd - spacing) * Math.random();
7240
+ // Mix the even spacing and random variation based on the randomness parameter
7241
+ const randomValue = spacing * (1 - randomness) + randomVariation * randomness;
7242
+ values.push(clamp$1(randomValue, previousValue, 1));
7243
+ }
7244
+ values.push(1);
7245
+ return linear(...values);
7246
+ };
7247
+
7081
7248
  var index$3 = /*#__PURE__*/Object.freeze({
7082
7249
  __proto__: null,
7250
+ Spring: Spring,
7251
+ createSpring: createSpring,
7083
7252
  cubicBezier: cubicBezier,
7084
7253
  eases: eases,
7085
7254
  irregular: irregular,
7086
7255
  linear: linear,
7087
- none: none,
7256
+ spring: spring,
7088
7257
  steps: steps
7089
7258
  });
7090
7259
 
@@ -8140,21 +8309,11 @@
8140
8309
  */
8141
8310
  const easingToLinear = (fn, samples = 100) => {
8142
8311
  const points = [];
8143
- for (let i = 0; i <= samples; i++) points.push(fn(i / samples));
8312
+ for (let i = 0; i <= samples; i++) points.push(round$1(fn(i / samples), 4));
8144
8313
  return `linear(${points.join(', ')})`;
8145
8314
  };
8146
8315
 
8147
- const WAAPIEasesLookups = {
8148
- in: 'ease-in',
8149
- out: 'ease-out',
8150
- inOut: 'ease-in-out',
8151
- };
8152
-
8153
- const WAAPIeases = /*#__PURE__*/(() => {
8154
- const list = {};
8155
- for (let type in easeTypes) list[type] = (/** @type {String|Number} */p) => easeTypes[type](easeInPower(p));
8156
- return /** @type {Record<String, EasingFunction>} */(list);
8157
- })();
8316
+ const WAAPIEasesLookups = {};
8158
8317
 
8159
8318
  /**
8160
8319
  * @param {EasingParam} ease
@@ -8175,9 +8334,10 @@
8175
8334
  } else if (stringStartsWith(ease, 'cubicB')) {
8176
8335
  parsedEase = toLowerCase(ease);
8177
8336
  } else {
8178
- const parsed = parseEaseString(ease, WAAPIeases, WAAPIEasesLookups);
8337
+ const parsed = parseEaseString(ease);
8179
8338
  if (isFnc(parsed)) parsedEase = parsed === none ? 'linear' : easingToLinear(parsed);
8180
8339
  }
8340
+ // Only cache string based easing name, otherwise function arguments get lost
8181
8341
  WAAPIEasesLookups[ease] = parsedEase;
8182
8342
  } else if (isFnc(ease)) {
8183
8343
  const easing = easingToLinear(ease);
@@ -8218,7 +8378,8 @@
8218
8378
  * @return {String}
8219
8379
  */
8220
8380
  const normalizeTweenValue = (propName, value, $el, i, targetsLength) => {
8221
- let v = getFunctionValue(/** @type {any} */(value), $el, i, targetsLength);
8381
+ // Do not try to compute strings with getFunctionValue otherwise it will convert CSS variables
8382
+ let v = isStr(value) ? value : getFunctionValue(/** @type {any} */(value), $el, i, targetsLength);
8222
8383
  if (!isNum(v)) return v;
8223
8384
  if (commonDefaultPXProperties.includes(propName) || stringStartsWith(propName, 'translate')) return `${v}px`;
8224
8385
  if (stringStartsWith(propName, 'rotate') || stringStartsWith(propName, 'skew')) return `${v}deg`;
@@ -8298,7 +8459,7 @@
8298
8459
  /** @type {PlaybackDirection} */
8299
8460
  const direction = alternate ? reversed ? 'alternate-reverse' : 'alternate' : reversed ? 'reverse' : 'normal';
8300
8461
  /** @type {FillMode} */
8301
- const fill = 'forwards';
8462
+ const fill = 'both'; // We use 'both' here because the animation can be reversed during playback
8302
8463
  /** @type {String} */
8303
8464
  const easing = parseWAAPIEasing(ease);
8304
8465
  const timeScale = (globals.timeScale === 1 ? 1 : K);
@@ -8310,7 +8471,7 @@
8310
8471
  /** @type {globalThis.Animation}] */
8311
8472
  this.controlAnimation = null;
8312
8473
  /** @type {Callback<this>} */
8313
- this.onComplete = params.onComplete || noop;
8474
+ this.onComplete = params.onComplete || /** @type {Callback<WAAPIAnimation>} */(/** @type {unknown} */(globals.defaults.onComplete));
8314
8475
  /** @type {Number} */
8315
8476
  this.duration = 0;
8316
8477
  /** @type {Boolean} */
@@ -8321,6 +8482,8 @@
8321
8482
  this.paused = !autoplay || scroll !== false;
8322
8483
  /** @type {Boolean} */
8323
8484
  this.reversed = reversed;
8485
+ /** @type {Boolean} */
8486
+ this.persist = setValue(params.persist, globals.defaults.persist);
8324
8487
  /** @type {Boolean|ScrollObserver} */
8325
8488
  this.autoplay = autoplay;
8326
8489
  /** @type {Number} */
@@ -8329,17 +8492,18 @@
8329
8492
  this._resolve = noop; // Used by .then()
8330
8493
  /** @type {Number} */
8331
8494
  this._completed = 0;
8332
- /** @type {Array<Object>}] */
8333
- this._inlineStyles = parsedTargets.map($el => $el.getAttribute('style'));
8495
+ /** @type {Array.<Object>} */
8496
+ this._inlineStyles = [];
8334
8497
 
8335
8498
  parsedTargets.forEach(($el, i) => {
8336
8499
 
8337
8500
  const cachedTransforms = $el[transformsSymbol];
8338
-
8339
8501
  const hasIndividualTransforms = validIndividualTransforms.some(t => params.hasOwnProperty(t));
8502
+ const elStyle = $el.style;
8503
+ const inlineStyles = this._inlineStyles[i] = {};
8340
8504
 
8341
8505
  /** @type {Number} */
8342
- const duration = (spring ? /** @type {Spring} */(spring).duration : getFunctionValue(setValue(params.duration, globals.defaults.duration), $el, i, targetsLength)) * timeScale;
8506
+ const duration = (spring ? /** @type {Spring} */(spring).settlingDuration : getFunctionValue(setValue(params.duration, globals.defaults.duration), $el, i, targetsLength)) * timeScale;
8343
8507
  /** @type {Number} */
8344
8508
  const delay = getFunctionValue(setValue(params.delay, globals.defaults.delay), $el, i, targetsLength) * timeScale;
8345
8509
  /** @type {CompositeOperation} */
@@ -8353,6 +8517,12 @@
8353
8517
  const tweenParams = { iterations, direction, fill, easing, duration, delay, composite };
8354
8518
  const propertyValue = params[name];
8355
8519
  const individualTransformProperty = hasIndividualTransforms ? validTransforms.includes(name) ? name : shortTransforms.get(name) : false;
8520
+
8521
+ const styleName = individualTransformProperty ? 'transform' : name;
8522
+ if (!inlineStyles[styleName]) {
8523
+ inlineStyles[styleName] = elStyle[styleName];
8524
+ }
8525
+
8356
8526
  let parsedPropertyValue;
8357
8527
  if (isObj(propertyValue)) {
8358
8528
  const tweenOptions = /** @type {WAAPITweenOptions} */(propertyValue);
@@ -8361,7 +8531,7 @@
8361
8531
  const to = /** @type {WAAPITweenOptions} */(tweenOptions).to;
8362
8532
  const from = /** @type {WAAPITweenOptions} */(tweenOptions).from;
8363
8533
  /** @type {Number} */
8364
- tweenParams.duration = (tweenOptionsSpring ? /** @type {Spring} */(tweenOptionsSpring).duration : getFunctionValue(setValue(tweenOptions.duration, duration), $el, i, targetsLength)) * timeScale;
8534
+ tweenParams.duration = (tweenOptionsSpring ? /** @type {Spring} */(tweenOptionsSpring).settlingDuration : getFunctionValue(setValue(tweenOptions.duration, duration), $el, i, targetsLength)) * timeScale;
8365
8535
  /** @type {Number} */
8366
8536
  tweenParams.delay = getFunctionValue(setValue(tweenOptions.delay, delay), $el, i, targetsLength) * timeScale;
8367
8537
  /** @type {CompositeOperation} */
@@ -8378,10 +8548,10 @@
8378
8548
  addWAAPIAnimation(this, $el, name, keyframes, tweenParams);
8379
8549
  if (!isUnd(from)) {
8380
8550
  if (!individualTransformProperty) {
8381
- $el.style[name] = keyframes[name][0];
8551
+ elStyle[name] = keyframes[name][0];
8382
8552
  } else {
8383
8553
  const key = `--${individualTransformProperty}`;
8384
- $el.style.setProperty(key, keyframes[key][0]);
8554
+ elStyle.setProperty(key, keyframes[key][0]);
8385
8555
  }
8386
8556
  }
8387
8557
  } else {
@@ -8402,7 +8572,7 @@
8402
8572
  for (let t in cachedTransforms) {
8403
8573
  transforms += `${transformsFragmentStrings[t]}var(--${t})) `;
8404
8574
  }
8405
- $el.style.transform = transforms;
8575
+ elStyle.transform = transforms;
8406
8576
  }
8407
8577
  });
8408
8578
 
@@ -8447,7 +8617,8 @@
8447
8617
  // Make sure the animation playState is not 'paused' in order to properly trigger an onfinish callback.
8448
8618
  // 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.
8449
8619
  // https://developer.mozilla.org/en-US/docs/Web/API/Animation/finish_event
8450
- if (t >= this.duration) anim.play();
8620
+ // This is not needed for persisting animations since they never finish.
8621
+ if (!this.persist && t >= this.duration) anim.play();
8451
8622
  anim.currentTime = t;
8452
8623
  });
8453
8624
  }
@@ -8517,13 +8688,30 @@
8517
8688
  }
8518
8689
 
8519
8690
  cancel() {
8520
- this.forEach('cancel');
8521
- return this.pause();
8691
+ this.muteCallbacks = true; // This prevents triggering the onComplete callback and resolving the Promise
8692
+ return this.commitStyles().forEach('cancel');
8522
8693
  }
8523
8694
 
8524
8695
  revert() {
8525
- this.cancel();
8526
- this.targets.forEach(($el, i) => $el.setAttribute('style', this._inlineStyles[i]) );
8696
+ // NOTE: We need a better way to revert the transforms, since right now the entire transform property value is reverted,
8697
+ // This means if you have multiple animations animating different transforms on the same target,
8698
+ // reverting one of them will also override the transform property of the other animations.
8699
+ // A better approach would be to store the original custom property values is they exist instead of the entire transform value,
8700
+ // and update the CSS variables with the orignal value
8701
+ this.cancel().targets.forEach(($el, i) => {
8702
+ const targetStyle = $el.style;
8703
+ const targetInlineStyles = this._inlineStyles[i];
8704
+ for (let name in targetInlineStyles) {
8705
+ const originalInlinedValue = targetInlineStyles[name];
8706
+ if (isUnd(originalInlinedValue) || originalInlinedValue === emptyString) {
8707
+ targetStyle.removeProperty(toLowerCase(name));
8708
+ } else {
8709
+ targetStyle[name] = originalInlinedValue;
8710
+ }
8711
+ }
8712
+ // Remove style attribute if empty
8713
+ if ($el.getAttribute('style') === emptyString) $el.removeAttribute('style');
8714
+ });
8527
8715
  return this;
8528
8716
  }
8529
8717
 
@@ -8593,7 +8781,6 @@
8593
8781
  exports.linear = linear;
8594
8782
  exports.mapRange = mapRange;
8595
8783
  exports.morphTo = morphTo;
8596
- exports.none = none;
8597
8784
  exports.onScroll = onScroll;
8598
8785
  exports.padEnd = padEnd;
8599
8786
  exports.padStart = padStart;
@@ -8609,6 +8796,7 @@
8609
8796
  exports.snap = snap;
8610
8797
  exports.split = split;
8611
8798
  exports.splitText = splitText;
8799
+ exports.spring = spring;
8612
8800
  exports.stagger = stagger;
8613
8801
  exports.steps = steps;
8614
8802
  exports.svg = index$1;