animejs 4.2.0-beta.0 → 4.2.1

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 (147) hide show
  1. package/README.md +6 -1
  2. package/dist/bundles/anime.esm.js +543 -304
  3. package/dist/bundles/anime.esm.min.js +2 -2
  4. package/dist/bundles/anime.umd.js +544 -305
  5. package/dist/bundles/anime.umd.min.js +2 -2
  6. package/dist/modules/animatable/animatable.cjs +4 -4
  7. package/dist/modules/animatable/animatable.js +3 -3
  8. package/dist/modules/animatable/index.cjs +1 -1
  9. package/dist/modules/animatable/index.js +1 -1
  10. package/dist/modules/animation/additive.cjs +1 -1
  11. package/dist/modules/animation/additive.js +1 -1
  12. package/dist/modules/animation/animation.cjs +28 -17
  13. package/dist/modules/animation/animation.d.ts +8 -5
  14. package/dist/modules/animation/animation.js +27 -16
  15. package/dist/modules/animation/composition.cjs +1 -1
  16. package/dist/modules/animation/composition.js +1 -1
  17. package/dist/modules/animation/index.cjs +1 -1
  18. package/dist/modules/animation/index.js +1 -1
  19. package/dist/modules/core/clock.cjs +1 -1
  20. package/dist/modules/core/clock.js +1 -1
  21. package/dist/modules/core/colors.cjs +1 -1
  22. package/dist/modules/core/colors.js +1 -1
  23. package/dist/modules/core/consts.cjs +7 -2
  24. package/dist/modules/core/consts.d.ts +2 -0
  25. package/dist/modules/core/consts.js +6 -3
  26. package/dist/modules/core/globals.cjs +3 -2
  27. package/dist/modules/core/globals.js +3 -2
  28. package/dist/modules/core/helpers.cjs +1 -1
  29. package/dist/modules/core/helpers.js +1 -1
  30. package/dist/modules/core/render.cjs +4 -2
  31. package/dist/modules/core/render.js +4 -2
  32. package/dist/modules/core/styles.cjs +8 -8
  33. package/dist/modules/core/styles.js +10 -10
  34. package/dist/modules/core/targets.cjs +1 -1
  35. package/dist/modules/core/targets.js +1 -1
  36. package/dist/modules/core/transforms.cjs +1 -1
  37. package/dist/modules/core/transforms.js +1 -1
  38. package/dist/modules/core/units.cjs +1 -1
  39. package/dist/modules/core/units.js +1 -1
  40. package/dist/modules/core/values.cjs +17 -6
  41. package/dist/modules/core/values.js +19 -8
  42. package/dist/modules/draggable/draggable.cjs +32 -19
  43. package/dist/modules/draggable/draggable.d.ts +3 -1
  44. package/dist/modules/draggable/draggable.js +28 -15
  45. package/dist/modules/draggable/index.cjs +1 -1
  46. package/dist/modules/draggable/index.js +1 -1
  47. package/dist/modules/easings/{cubic-bezier.cjs → cubic-bezier/index.cjs} +4 -4
  48. package/dist/modules/easings/{cubic-bezier.d.ts → cubic-bezier/index.d.ts} +1 -1
  49. package/dist/modules/easings/{cubic-bezier.js → cubic-bezier/index.js} +4 -4
  50. package/dist/modules/easings/eases/index.cjs +14 -0
  51. package/dist/modules/easings/eases/index.d.ts +1 -0
  52. package/dist/modules/easings/eases/index.js +8 -0
  53. package/dist/modules/easings/{eases.cjs → eases/parser.cjs} +69 -27
  54. package/dist/modules/easings/{eases.d.ts → eases/parser.d.ts} +31 -17
  55. package/dist/modules/easings/{eases.js → eases/parser.js} +60 -21
  56. package/dist/modules/easings/index.cjs +15 -13
  57. package/dist/modules/easings/index.d.ts +6 -6
  58. package/dist/modules/easings/index.js +7 -7
  59. package/dist/modules/easings/{irregular.cjs → irregular/index.cjs} +5 -5
  60. package/dist/modules/easings/{irregular.d.ts → irregular/index.d.ts} +1 -1
  61. package/dist/modules/easings/{irregular.js → irregular/index.js} +4 -4
  62. package/dist/modules/easings/{linear.cjs → linear/index.cjs} +4 -4
  63. package/dist/modules/easings/{linear.d.ts → linear/index.d.ts} +1 -1
  64. package/dist/modules/easings/{linear.js → linear/index.js} +4 -4
  65. package/dist/modules/easings/none.cjs +1 -1
  66. package/dist/modules/easings/none.js +1 -1
  67. package/dist/modules/easings/spring/index.cjs +255 -0
  68. package/dist/modules/{spring/spring.d.ts → easings/spring/index.d.ts} +21 -5
  69. package/dist/modules/easings/spring/index.js +251 -0
  70. package/dist/modules/easings/{steps.cjs → steps/index.cjs} +3 -3
  71. package/dist/modules/easings/{steps.d.ts → steps/index.d.ts} +1 -1
  72. package/dist/modules/easings/{steps.js → steps/index.js} +3 -3
  73. package/dist/modules/engine/engine.cjs +1 -1
  74. package/dist/modules/engine/engine.js +1 -1
  75. package/dist/modules/engine/index.cjs +1 -1
  76. package/dist/modules/engine/index.js +1 -1
  77. package/dist/modules/events/index.cjs +1 -1
  78. package/dist/modules/events/index.js +1 -1
  79. package/dist/modules/events/scroll.cjs +17 -9
  80. package/dist/modules/events/scroll.d.ts +4 -0
  81. package/dist/modules/events/scroll.js +16 -8
  82. package/dist/modules/index.cjs +15 -16
  83. package/dist/modules/index.d.ts +0 -1
  84. package/dist/modules/index.js +7 -8
  85. package/dist/modules/scope/index.cjs +1 -1
  86. package/dist/modules/scope/index.js +1 -1
  87. package/dist/modules/scope/scope.cjs +1 -1
  88. package/dist/modules/scope/scope.js +1 -1
  89. package/dist/modules/svg/drawable.cjs +1 -1
  90. package/dist/modules/svg/drawable.js +1 -1
  91. package/dist/modules/svg/helpers.cjs +1 -1
  92. package/dist/modules/svg/helpers.js +1 -1
  93. package/dist/modules/svg/index.cjs +1 -1
  94. package/dist/modules/svg/index.js +1 -1
  95. package/dist/modules/svg/morphto.cjs +12 -2
  96. package/dist/modules/svg/morphto.js +12 -2
  97. package/dist/modules/svg/motionpath.cjs +18 -11
  98. package/dist/modules/svg/motionpath.d.ts +1 -1
  99. package/dist/modules/svg/motionpath.js +18 -11
  100. package/dist/modules/text/index.cjs +1 -1
  101. package/dist/modules/text/index.js +1 -1
  102. package/dist/modules/text/split.cjs +1 -1
  103. package/dist/modules/text/split.js +1 -1
  104. package/dist/modules/timeline/index.cjs +1 -1
  105. package/dist/modules/timeline/index.js +1 -1
  106. package/dist/modules/timeline/position.cjs +1 -1
  107. package/dist/modules/timeline/position.js +1 -1
  108. package/dist/modules/timeline/timeline.cjs +11 -7
  109. package/dist/modules/timeline/timeline.d.ts +8 -3
  110. package/dist/modules/timeline/timeline.js +10 -6
  111. package/dist/modules/timer/index.cjs +1 -1
  112. package/dist/modules/timer/index.js +1 -1
  113. package/dist/modules/timer/timer.cjs +17 -14
  114. package/dist/modules/timer/timer.d.ts +12 -7
  115. package/dist/modules/timer/timer.js +17 -14
  116. package/dist/modules/types/index.d.ts +35 -14
  117. package/dist/modules/utils/chainable.cjs +1 -1
  118. package/dist/modules/utils/chainable.js +1 -1
  119. package/dist/modules/utils/index.cjs +1 -1
  120. package/dist/modules/utils/index.js +1 -1
  121. package/dist/modules/utils/number.cjs +1 -1
  122. package/dist/modules/utils/number.js +1 -1
  123. package/dist/modules/utils/random.cjs +1 -1
  124. package/dist/modules/utils/random.js +1 -1
  125. package/dist/modules/utils/stagger.cjs +4 -4
  126. package/dist/modules/utils/stagger.js +3 -3
  127. package/dist/modules/utils/target.cjs +1 -1
  128. package/dist/modules/utils/target.js +1 -1
  129. package/dist/modules/utils/time.cjs +1 -1
  130. package/dist/modules/utils/time.js +1 -1
  131. package/dist/modules/waapi/composition.cjs +11 -5
  132. package/dist/modules/waapi/composition.d.ts +1 -1
  133. package/dist/modules/waapi/composition.js +11 -5
  134. package/dist/modules/waapi/index.cjs +1 -1
  135. package/dist/modules/waapi/index.js +1 -1
  136. package/dist/modules/waapi/waapi.cjs +58 -36
  137. package/dist/modules/waapi/waapi.d.ts +12 -7
  138. package/dist/modules/waapi/waapi.js +59 -37
  139. package/package.json +48 -13
  140. package/dist/modules/easings/parser.cjs +0 -59
  141. package/dist/modules/easings/parser.d.ts +0 -21
  142. package/dist/modules/easings/parser.js +0 -55
  143. package/dist/modules/spring/index.cjs +0 -15
  144. package/dist/modules/spring/index.d.ts +0 -1
  145. package/dist/modules/spring/index.js +0 -8
  146. package/dist/modules/spring/spring.cjs +0 -133
  147. package/dist/modules/spring/spring.js +0 -130
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Anime.js - ESM bundle
3
- * @version v4.2.0
3
+ * @version v4.2.1
4
4
  * @license MIT
5
5
  * @copyright 2025 - Julian Garnier
6
6
  */
@@ -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
@@ -375,17 +385,13 @@
375
385
  * @typedef {WAAPITweenValue|WAAPIFunctionValue|Array<String|Number|WAAPIFunctionValue>} WAAPIKeyframeValue
376
386
  */
377
387
 
378
- /**
379
- * @typedef {(animation: WAAPIAnimation) => void} WAAPICallback
380
- */
381
-
382
388
  /**
383
389
  * @typedef {Object} WAAPITweenOptions
384
390
  * @property {WAAPIKeyframeValue} [to]
385
391
  * @property {WAAPIKeyframeValue} [from]
386
392
  * @property {Number|WAAPIFunctionValue} [duration]
387
393
  * @property {Number|WAAPIFunctionValue} [delay]
388
- * @property {EasingParam} [ease]
394
+ * @property {WAAPIEasingParam} [ease]
389
395
  * @property {CompositeOperation} [composition]
390
396
  */
391
397
 
@@ -398,13 +404,14 @@
398
404
  * @property {Number} [playbackRate]
399
405
  * @property {Number|WAAPIFunctionValue} [duration]
400
406
  * @property {Number|WAAPIFunctionValue} [delay]
401
- * @property {EasingParam} [ease]
407
+ * @property {WAAPIEasingParam} [ease]
402
408
  * @property {CompositeOperation} [composition]
403
- * @property {WAAPICallback} [onComplete]
409
+ * @property {Boolean} [persist]
410
+ * @property {Callback<WAAPIAnimation>} [onComplete]
404
411
  */
405
412
 
406
413
  /**
407
- * @typedef {Record<String, WAAPIKeyframeValue | WAAPIAnimationOptions | Boolean | ScrollObserver | WAAPICallback | EasingParam | WAAPITweenOptions> & WAAPIAnimationOptions} WAAPIAnimationParams
414
+ * @typedef {Record<String, WAAPIKeyframeValue | WAAPIAnimationOptions | Boolean | ScrollObserver | Callback<WAAPIAnimation> | WAAPIEasingParam | WAAPITweenOptions> & WAAPIAnimationOptions} WAAPIAnimationParams
408
415
  */
409
416
 
410
417
  // Animatable types
@@ -547,6 +554,12 @@
547
554
  * @property {String} [onGrab]
548
555
  */
549
556
 
557
+ /**
558
+ * @typedef {Object} DraggableDragThresholdParams
559
+ * @property {Number} [mouse]
560
+ * @property {Number} [touch]
561
+ */
562
+
550
563
  /**
551
564
  * @typedef {Object} DraggableParams
552
565
  * @property {DOMTargetSelector} [trigger]
@@ -559,6 +572,7 @@
559
572
  * @property {Number|((draggable: Draggable) => Number)} [containerFriction]
560
573
  * @property {Number|((draggable: Draggable) => Number)} [releaseContainerFriction]
561
574
  * @property {Number|((draggable: Draggable) => Number)} [dragSpeed]
575
+ * @property {Number|DraggableDragThresholdParams|((draggable: Draggable) => Number|DraggableDragThresholdParams)} [dragThreshold]
562
576
  * @property {Number|((draggable: Draggable) => Number)} [scrollSpeed]
563
577
  * @property {Number|((draggable: Draggable) => Number)} [scrollThreshold]
564
578
  * @property {Number|((draggable: Draggable) => Number)} [minVelocity]
@@ -682,6 +696,8 @@ const maxFps = 120;
682
696
  // Strings
683
697
 
684
698
  const emptyString = '';
699
+ const cssVarPrefix = 'var(';
700
+
685
701
  const shortTransforms = /*#__PURE__*/ (() => {
686
702
  const map = new Map();
687
703
  map.set('x', 'translateX');
@@ -705,9 +721,9 @@ const validTransforms = [
705
721
  'skew',
706
722
  'skewX',
707
723
  'skewY',
708
- 'perspective',
709
724
  'matrix',
710
725
  'matrix3d',
726
+ 'perspective',
711
727
  ];
712
728
 
713
729
  const transformsFragmentStrings = /*#__PURE__*/ validTransforms.reduce((a, v) => ({...a, [v]: v + '('}), {});
@@ -731,6 +747,7 @@ const unitsExecRgx = /^([-+]?\d*\.?\d+(?:e[-+]?\d+)?)([a-z]+|%)$/i;
731
747
  const lowerCaseRgx = /([a-z])([A-Z])/g;
732
748
  const transformsExecRgx = /(\w+)(\([^)]+\)+)/g; // Match inline transforms with cacl() values, returns the value wrapped in ()
733
749
  const relativeValuesExecRgx = /(\*=|\+=|-=)/;
750
+ const cssVariableMatchRgx = /var\(\s*(--[\w-]+)(?:\s*,\s*([^)]+))?\s*\)/;
734
751
 
735
752
 
736
753
 
@@ -745,6 +762,7 @@ const defaults = {
745
762
  reversed: false,
746
763
  alternate: false,
747
764
  autoplay: true,
765
+ persist: false,
748
766
  duration: K,
749
767
  delay: 0,
750
768
  loopDelay: 0,
@@ -778,7 +796,7 @@ const globals = {
778
796
  tickThreshold: 200,
779
797
  };
780
798
 
781
- const globalVersions = { version: '4.2.0', engine: null };
799
+ const globalVersions = { version: '4.2.1', engine: null };
782
800
 
783
801
  if (isBrowser) {
784
802
  if (!win.AnimeJS) win.AnimeJS = [];
@@ -1168,19 +1186,30 @@ const setValue = (targetValue, defaultValue) => {
1168
1186
  * @return {any}
1169
1187
  */
1170
1188
  const getFunctionValue = (value, target, index, total, store) => {
1189
+ let func;
1171
1190
  if (isFnc(value)) {
1172
- const func = () => {
1191
+ func = () => {
1173
1192
  const computed = /** @type {Function} */(value)(target, index, total);
1174
1193
  // Fallback to 0 if the function returns undefined / NaN / null / false / 0
1175
1194
  return !isNaN(+computed) ? +computed : computed || 0;
1176
1195
  };
1177
- if (store) {
1178
- store.func = func;
1179
- }
1180
- return func();
1196
+ } else if (isStr(value) && stringStartsWith(value, cssVarPrefix)) {
1197
+ func = () => {
1198
+ const match = value.match(cssVariableMatchRgx);
1199
+ const cssVarName = match[1];
1200
+ const fallbackValue = match[2];
1201
+ let computed = getComputedStyle(/** @type {HTMLElement} */(target))?.getPropertyValue(cssVarName);
1202
+ // Use fallback if CSS variable is not set or empty
1203
+ if ((!computed || computed.trim() === emptyString) && fallbackValue) {
1204
+ computed = fallbackValue.trim();
1205
+ }
1206
+ return computed || 0;
1207
+ };
1181
1208
  } else {
1182
1209
  return value;
1183
1210
  }
1211
+ if (store) store.func = func;
1212
+ return func();
1184
1213
  };
1185
1214
 
1186
1215
  /**
@@ -1587,7 +1616,9 @@ const render = (tickable, time, muteCallbacks, internalRender, tickMode) => {
1587
1616
  // Handle setters on timeline differently and allow re-trigering the onComplete callback when seeking backwards
1588
1617
  if (parent && isSetter) {
1589
1618
  if (!muteCallbacks && (
1590
- (parent.began && !isRunningBackwards && tickableAbsoluteTime >= duration && !completed) ||
1619
+ // (tickableAbsoluteTime > 0 instead) of (tickableAbsoluteTime >= duration) to prevent floating point precision issues
1620
+ // see: https://github.com/juliangarnier/anime/issues/1088
1621
+ (parent.began && !isRunningBackwards && tickableAbsoluteTime > 0 && !completed) ||
1591
1622
  (isRunningBackwards && tickableAbsoluteTime <= minValue && completed)
1592
1623
  )) {
1593
1624
  tickable.onComplete(/** @type {CallbackArgument} */(tickable));
@@ -1689,12 +1720,11 @@ const tick = (tickable, time, muteCallbacks, internalRender, tickMode) => {
1689
1720
  }
1690
1721
  };
1691
1722
 
1692
- const propertyNamesCache = {};
1693
-
1694
1723
 
1695
1724
 
1696
1725
 
1697
1726
 
1727
+ const propertyNamesCache = {};
1698
1728
 
1699
1729
  /**
1700
1730
  * @param {String} propertyName
@@ -1742,10 +1772,11 @@ const cleanInlineStyles = renderable => {
1742
1772
  const tweenTarget = tween.target;
1743
1773
  if (tweenTarget[isDomSymbol]) {
1744
1774
  const targetStyle = /** @type {DOMTarget} */(tweenTarget).style;
1745
- const originalInlinedValue = animation._inlineStyles[tweenProperty];
1775
+ const originalInlinedValue = tween._inlineValue;
1776
+ const tweenHadNoInlineValue = isNil(originalInlinedValue) || originalInlinedValue === emptyString;
1746
1777
  if (tween._tweenType === tweenTypes.TRANSFORM) {
1747
1778
  const cachedTransforms = tweenTarget[transformsSymbol];
1748
- if (isUnd(originalInlinedValue) || originalInlinedValue === emptyString) {
1779
+ if (tweenHadNoInlineValue) {
1749
1780
  delete cachedTransforms[tweenProperty];
1750
1781
  } else {
1751
1782
  cachedTransforms[tweenProperty] = originalInlinedValue;
@@ -1762,8 +1793,8 @@ const cleanInlineStyles = renderable => {
1762
1793
  }
1763
1794
  }
1764
1795
  } else {
1765
- if (isUnd(originalInlinedValue) || originalInlinedValue === emptyString) {
1766
- targetStyle.removeProperty(tweenProperty);
1796
+ if (tweenHadNoInlineValue) {
1797
+ targetStyle.removeProperty(toLowerCase(tweenProperty));
1767
1798
  } else {
1768
1799
  targetStyle[tweenProperty] = originalInlinedValue;
1769
1800
  }
@@ -2452,7 +2483,7 @@ const reviveTimer = timer => {
2452
2483
  if (timer._hasChildren) {
2453
2484
  forEachChildren(timer, reviveTimer);
2454
2485
  } else {
2455
- forEachChildren(timer, (/** @type {Tween} tween*/tween) => {
2486
+ forEachChildren(timer, (/** @type {Tween} tween */tween) => {
2456
2487
  if (tween._composition !== compositionTypes.none) {
2457
2488
  composeTween(tween, getTweenSiblings(tween.target, tween.property));
2458
2489
  }
@@ -2509,7 +2540,6 @@ class Timer extends Clock {
2509
2540
  /** @type {Number} */(timerLoop) < 0 ? Infinity :
2510
2541
  /** @type {Number} */(timerLoop) + 1;
2511
2542
 
2512
-
2513
2543
  let offsetPosition = 0;
2514
2544
 
2515
2545
  if (parent) {
@@ -2599,7 +2629,7 @@ class Timer extends Clock {
2599
2629
  }
2600
2630
 
2601
2631
  set cancelled(cancelled) {
2602
- cancelled ? this.cancel() : this.reset(1).play();
2632
+ cancelled ? this.cancel() : this.reset(true).play();
2603
2633
  }
2604
2634
 
2605
2635
  get currentTime() {
@@ -2664,10 +2694,10 @@ class Timer extends Clock {
2664
2694
  }
2665
2695
 
2666
2696
  /**
2667
- * @param {Number} internalRender
2697
+ * @param {Boolean} [softReset]
2668
2698
  * @return {this}
2669
2699
  */
2670
- reset(internalRender = 0) {
2700
+ reset(softReset = false) {
2671
2701
  // If cancelled, revive the timer before rendering in order to have propertly composed tweens siblings
2672
2702
  reviveTimer(this);
2673
2703
  if (this._reversed && !this._reverse) this.reversed = false;
@@ -2676,7 +2706,7 @@ class Timer extends Clock {
2676
2706
  // NOTE: This is only required for Timelines and might be better to move to the Timeline class?
2677
2707
  this._iterationTime = this.iterationDuration;
2678
2708
  // Set tickMode to tickModes.FORCE to force rendering
2679
- tick(this, 0, 1, internalRender, tickModes.FORCE);
2709
+ tick(this, 0, 1, ~~softReset, tickModes.FORCE);
2680
2710
  // Reset timer properties after revive / render to make sure the props are not updated again
2681
2711
  resetTimerProperties(this);
2682
2712
  // Also reset children properties
@@ -2687,16 +2717,16 @@ class Timer extends Clock {
2687
2717
  }
2688
2718
 
2689
2719
  /**
2690
- * @param {Number} internalRender
2720
+ * @param {Boolean} internalRender
2691
2721
  * @return {this}
2692
2722
  */
2693
- init(internalRender = 0) {
2723
+ init(internalRender = false) {
2694
2724
  this.fps = this._fps;
2695
2725
  this.speed = this._speed;
2696
2726
  // Manually calling .init() on timelines should render all children intial state
2697
2727
  // Forces all children to render once then render to 0 when reseted
2698
2728
  if (!internalRender && this._hasChildren) {
2699
- tick(this, this.duration, 1, internalRender, tickModes.FORCE);
2729
+ tick(this, this.duration, 1, ~~internalRender, tickModes.FORCE);
2700
2730
  }
2701
2731
  this.reset(internalRender);
2702
2732
  // Make sure to set autoplay to false to child timers so it doesn't attempt to autoplay / link
@@ -2750,7 +2780,7 @@ class Timer extends Clock {
2750
2780
 
2751
2781
  /** @return {this} */
2752
2782
  restart() {
2753
- return this.reset(0).resume();
2783
+ return this.reset().resume();
2754
2784
  }
2755
2785
 
2756
2786
  /**
@@ -2853,8 +2883,12 @@ class Timer extends Clock {
2853
2883
  }
2854
2884
 
2855
2885
  /**
2856
- * @param {Callback<this>} [callback]
2857
- * @return {Promise}
2886
+ * @typedef {this & {then: null}} ResolvedTimer
2887
+ */
2888
+
2889
+ /**
2890
+ * @param {Callback<ResolvedTimer>} [callback]
2891
+ * @return Promise<this>
2858
2892
  */
2859
2893
  then(callback = noop) {
2860
2894
  const then = this.then;
@@ -2862,7 +2896,7 @@ class Timer extends Clock {
2862
2896
  // this.then = null prevents infinite recursion if returned by an async function
2863
2897
  // https://github.com/juliangarnierorg/anime-beta/issues/26
2864
2898
  this.then = null;
2865
- callback(this);
2899
+ callback(/** @type {ResolvedTimer} */(this));
2866
2900
  this.then = then;
2867
2901
  this._resolve = noop;
2868
2902
  };
@@ -3048,6 +3082,7 @@ const none = t => t;
3048
3082
 
3049
3083
 
3050
3084
 
3085
+
3051
3086
  /** @type {PowerEasing} */
3052
3087
  const easeInPower = (p = 1.68) => t => pow(t, +p);
3053
3088
 
@@ -3065,154 +3100,6 @@ const easeTypes = {
3065
3100
  outIn: easeIn => t => t < .5 ? (1 - easeIn(1 - t * 2)) / 2 : (easeIn(t * 2 - 1) + 1) / 2,
3066
3101
  };
3067
3102
 
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
3103
  /**
3217
3104
  * Easing functions adapted and simplified from https://robertpenner.com/easing/
3218
3105
  * (c) 2001 Robert Penner
@@ -3241,7 +3128,7 @@ const easeInFunctions = {
3241
3128
  return 1 / pow(4, 3 - b) - 7.5625 * pow((pow2 * 3 - 2) / 22 - t, 2);
3242
3129
  },
3243
3130
  /** @type {BackEasing} */
3244
- 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,
3245
3132
  /** @type {ElasticEasing} */
3246
3133
  Elastic: (amplitude = 1, period = .3) => {
3247
3134
  const a = clamp$1(+amplitude, 1, 10);
@@ -3254,10 +3141,8 @@ const easeInFunctions = {
3254
3141
 
3255
3142
  /**
3256
3143
  * @typedef {Object} EasesFunctions
3257
- * @property {typeof linear} linear
3258
- * @property {typeof irregular} irregular
3259
- * @property {typeof steps} steps
3260
- * @property {typeof cubicBezier} cubicBezier
3144
+ * @property {typeof none} linear
3145
+ * @property {typeof none} none
3261
3146
  * @property {PowerEasing} in
3262
3147
  * @property {PowerEasing} out
3263
3148
  * @property {PowerEasing} inOut
@@ -3305,7 +3190,7 @@ const easeInFunctions = {
3305
3190
  */
3306
3191
 
3307
3192
  const eases = (/*#__PURE__ */ (() => {
3308
- const list = { linear, irregular, steps, cubicBezier };
3193
+ const list = { linear: none, none: none };
3309
3194
  for (let type in easeTypes) {
3310
3195
  for (let name in easeInFunctions) {
3311
3196
  const easeIn = easeInFunctions[name];
@@ -3321,15 +3206,43 @@ const eases = (/*#__PURE__ */ (() => {
3321
3206
  })());
3322
3207
 
3323
3208
  /** @type {Record<String, EasingFunction>} */
3324
- 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('];
3325
3229
 
3326
3230
  /**
3327
3231
  * @param {EasingParam} ease
3328
3232
  * @return {EasingFunction}
3329
3233
  */
3330
- const parseEase = ease => isFnc(ease) ? ease :
3331
- isStr(ease) ? parseEaseString(/** @type {String} */(ease), eases, JSEasesLookups) :
3332
- 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
+ };
3333
3246
 
3334
3247
 
3335
3248
 
@@ -3337,6 +3250,7 @@ const parseEase = ease => isFnc(ease) ? ease :
3337
3250
  // TODO: Maybe move the objects creation to values.js and use the decompose function to create the base object
3338
3251
  const fromTargetObject = createDecomposedValueTargetObject();
3339
3252
  const toTargetObject = createDecomposedValueTargetObject();
3253
+ const inlineStylesStore = {};
3340
3254
  const toFunctionStore = { func: null };
3341
3255
  const keyframesTargetArray = [null];
3342
3256
  const fastSetValuesArray = [null, null];
@@ -3481,15 +3395,15 @@ class JSAnimation extends Timer {
3481
3395
  const animEase = animaPlaybackEase ? parseEase(animaPlaybackEase) : null;
3482
3396
  const hasSpring = !isUnd(ease) && !isUnd(/** @type {Spring} */(ease).ease);
3483
3397
  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);
3398
+ const tDuration = hasSpring ? /** @type {Spring} */(ease).settlingDuration : setValue(duration, animDefaults.duration);
3485
3399
  const tDelay = setValue(delay, animDefaults.delay);
3486
3400
  const tModifier = modifier || animDefaults.modifier;
3487
3401
  // If no composition is defined and the targets length is high (>= 1000) set the composition to 'none' (0) for faster tween creation
3488
3402
  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
3403
  // const absoluteOffsetTime = this._offset;
3492
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;
3493
3407
 
3494
3408
  let iterationDuration = NaN;
3495
3409
  let iterationDelay = NaN;
@@ -3591,7 +3505,7 @@ class JSAnimation extends Timer {
3591
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
3592
3506
  const tweenEasing = hasSpring ? /** @type {Spring} */(keyEasing).ease : keyEasing || tEasing;
3593
3507
  // 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);
3508
+ const tweenDuration = hasSpring ? /** @type {Spring} */(keyEasing).settlingDuration : getFunctionValue(setValue(key.duration, (l > 1 ? getFunctionValue(tDuration, target, ti, tl) / l : tDuration)), target, ti, tl);
3595
3509
  // Default delay value should only be applied to the first tween
3596
3510
  const tweenDelay = getFunctionValue(setValue(key.delay, (!tweenIndex ? tDelay : 0)), target, ti, tl);
3597
3511
  const computedComposition = getFunctionValue(setValue(key.composition, tComposition), target, ti, tl);
@@ -3641,7 +3555,7 @@ class JSAnimation extends Timer {
3641
3555
  }
3642
3556
  } else {
3643
3557
  decomposeRawValue(
3644
- getOriginalAnimatableValue(target, propName, tweenType, animInlineStyles),
3558
+ getOriginalAnimatableValue(target, propName, tweenType, inlineStylesStore),
3645
3559
  decomposedOriginalValue
3646
3560
  );
3647
3561
  if (decomposedOriginalValue.t === valueTypes.UNIT) {
@@ -3659,7 +3573,7 @@ class JSAnimation extends Timer {
3659
3573
  } else {
3660
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
3661
3575
  decomposeRawValue(parent && prevSibling && prevSibling.parent.parent === parent ? prevSibling._value :
3662
- getOriginalAnimatableValue(target, propName, tweenType, animInlineStyles), toTargetObject);
3576
+ getOriginalAnimatableValue(target, propName, tweenType, inlineStylesStore), toTargetObject);
3663
3577
  }
3664
3578
  }
3665
3579
  if (hasFromvalue) {
@@ -3670,7 +3584,7 @@ class JSAnimation extends Timer {
3670
3584
  } else {
3671
3585
  decomposeRawValue(parent && prevSibling && prevSibling.parent.parent === parent ? prevSibling._value :
3672
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
3673
- getOriginalAnimatableValue(target, propName, tweenType, animInlineStyles), fromTargetObject);
3587
+ getOriginalAnimatableValue(target, propName, tweenType, inlineStylesStore), fromTargetObject);
3674
3588
  }
3675
3589
  }
3676
3590
  }
@@ -3679,7 +3593,7 @@ class JSAnimation extends Timer {
3679
3593
  if (fromTargetObject.o) {
3680
3594
  fromTargetObject.n = getRelativeValue(
3681
3595
  !prevSibling ? decomposeRawValue(
3682
- getOriginalAnimatableValue(target, propName, tweenType, animInlineStyles),
3596
+ getOriginalAnimatableValue(target, propName, tweenType, inlineStylesStore),
3683
3597
  decomposedOriginalValue
3684
3598
  ).n : prevSibling._toNumber,
3685
3599
  fromTargetObject.n,
@@ -3735,6 +3649,10 @@ class JSAnimation extends Timer {
3735
3649
  // Rounding is necessary here to minimize floating point errors when working in seconds
3736
3650
  const tweenUpdateDuration = round$1(+tweenDuration || minValue, 12);
3737
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
+
3738
3656
  /** @type {Tween} */
3739
3657
  const tween = {
3740
3658
  parent: this,
@@ -3766,6 +3684,7 @@ class JSAnimation extends Timer {
3766
3684
  _isOverlapped: 0,
3767
3685
  _isOverridden: 0,
3768
3686
  _renderTransforms: 0,
3687
+ _inlineValue: inlineValue,
3769
3688
  _prevRep: null, // For replaced tween
3770
3689
  _nextRep: null, // For replaced tween
3771
3690
  _prevAdd: null, // For additive tween
@@ -3868,8 +3787,6 @@ class JSAnimation extends Timer {
3868
3787
  // this._offset += parent ? iterationDelay : 0;
3869
3788
  /** @type {Number} */
3870
3789
  this.iterationDuration = iterationDuration;
3871
- /** @type {{}} */
3872
- this._inlineStyles = animInlineStyles;
3873
3790
 
3874
3791
  if (!this._autoplay && shouldTriggerRender) this.onRender(this);
3875
3792
  }
@@ -3903,6 +3820,7 @@ class JSAnimation extends Timer {
3903
3820
  if (tweenFunc) {
3904
3821
  const ogValue = getOriginalAnimatableValue(tween.target, tween.property, tween._tweenType);
3905
3822
  decomposeRawValue(ogValue, decomposedOriginalValue);
3823
+ // TODO: Check for from / to Array based values here,
3906
3824
  decomposeRawValue(tweenFunc(), toTargetObject);
3907
3825
  tween._fromNumbers = cloneArray(decomposedOriginalValue.d);
3908
3826
  tween._fromNumber = decomposedOriginalValue.n;
@@ -3912,6 +3830,8 @@ class JSAnimation extends Timer {
3912
3830
  tween._toNumber = toTargetObject.o ? getRelativeValue(decomposedOriginalValue.n, toTargetObject.n, toTargetObject.o) : toTargetObject.n;
3913
3831
  }
3914
3832
  });
3833
+ // This forces setter animations to render once
3834
+ if (this.duration === minValue) this.restart();
3915
3835
  return this;
3916
3836
  }
3917
3837
 
@@ -3925,8 +3845,12 @@ class JSAnimation extends Timer {
3925
3845
  }
3926
3846
 
3927
3847
  /**
3928
- * @param {Callback<this>} [callback]
3929
- * @return {Promise}
3848
+ * @typedef {this & {then: null}} ResolvedJSAnimation
3849
+ */
3850
+
3851
+ /**
3852
+ * @param {Callback<ResolvedJSAnimation>} [callback]
3853
+ * @return Promise<this>
3930
3854
  */
3931
3855
  then(callback) {
3932
3856
  return super.then(callback);
@@ -3954,16 +3878,18 @@ const WAAPIAnimationsLookups = {
3954
3878
  * @param {DOMTarget} $el
3955
3879
  * @param {String} [property]
3956
3880
  * @param {WAAPIAnimation} [parent]
3881
+ * @return {globalThis.Animation}
3957
3882
  */
3958
3883
  const removeWAAPIAnimation = ($el, property, parent) => {
3959
3884
  let nextLookup = WAAPIAnimationsLookups._head;
3885
+ let anim;
3960
3886
  while (nextLookup) {
3961
3887
  const next = nextLookup._next;
3962
3888
  const matchTarget = nextLookup.$el === $el;
3963
3889
  const matchProperty = !property || nextLookup.property === property;
3964
3890
  const matchParent = !parent || nextLookup.parent === parent;
3965
3891
  if (matchTarget && matchProperty && matchParent) {
3966
- const anim = nextLookup.animation;
3892
+ anim = nextLookup.animation;
3967
3893
  try { anim.commitStyles(); } catch {} anim.cancel();
3968
3894
  removeChild(WAAPIAnimationsLookups, nextLookup);
3969
3895
  const lookupParent = nextLookup.parent;
@@ -3971,8 +3897,8 @@ const removeWAAPIAnimation = ($el, property, parent) => {
3971
3897
  lookupParent._completed++;
3972
3898
  if (lookupParent.animations.length === lookupParent._completed) {
3973
3899
  lookupParent.completed = true;
3900
+ lookupParent.paused = true;
3974
3901
  if (!lookupParent.muteCallbacks) {
3975
- lookupParent.paused = true;
3976
3902
  lookupParent.onComplete(lookupParent);
3977
3903
  lookupParent._resolve(lookupParent);
3978
3904
  }
@@ -3981,6 +3907,7 @@ const removeWAAPIAnimation = ($el, property, parent) => {
3981
3907
  }
3982
3908
  nextLookup = next;
3983
3909
  }
3910
+ return anim;
3984
3911
  };
3985
3912
 
3986
3913
  /**
@@ -3989,7 +3916,7 @@ const removeWAAPIAnimation = ($el, property, parent) => {
3989
3916
  * @param {String} property
3990
3917
  * @param {PropertyIndexedKeyframes} keyframes
3991
3918
  * @param {KeyframeAnimationOptions} params
3992
- * @retun {Animation}
3919
+ * @retun {globalThis.Animation}
3993
3920
  */
3994
3921
  const addWAAPIAnimation = (parent, $el, property, keyframes, params) => {
3995
3922
  const animation = $el.animate(keyframes, params);
@@ -4004,8 +3931,11 @@ const addWAAPIAnimation = (parent, $el, property, keyframes, params) => {
4004
3931
  removeWAAPIAnimation($el, property);
4005
3932
  addChild(WAAPIAnimationsLookups, { parent, animation, $el, property, _next: null, _prev: null });
4006
3933
  const handleRemove = () => { removeWAAPIAnimation($el, property, parent); };
3934
+ animation.oncancel = handleRemove;
4007
3935
  animation.onremove = handleRemove;
4008
- animation.onfinish = handleRemove;
3936
+ if (!parent.persist) {
3937
+ animation.onfinish = handleRemove;
3938
+ }
4009
3939
  return animation;
4010
3940
  };
4011
3941
 
@@ -4191,7 +4121,7 @@ function addTlChild(childParams, tl, timePosition, targets, index, length) {
4191
4121
  const tlChild = targets ?
4192
4122
  new JSAnimation(targets,/** @type {AnimationParams} */(childParams), tl, adjustedPosition, false, index, length) :
4193
4123
  new Timer(/** @type {TimerParams} */(childParams), tl, adjustedPosition);
4194
- tlChild.init(1);
4124
+ tlChild.init(true);
4195
4125
  // TODO: Might be better to insert at a position relative to startTime?
4196
4126
  addChild(tl, tlChild);
4197
4127
  forEachChildren(tl, (/** @type {Renderable} */child) => {
@@ -4295,7 +4225,7 @@ class Timeline extends Timer {
4295
4225
  parseTimelinePosition(this,a2),
4296
4226
  );
4297
4227
  }
4298
- return this.init(1); // 1 = internalRender
4228
+ return this.init(true);
4299
4229
  }
4300
4230
  }
4301
4231
 
@@ -4404,8 +4334,12 @@ class Timeline extends Timer {
4404
4334
  }
4405
4335
 
4406
4336
  /**
4407
- * @param {Callback<this>} [callback]
4408
- * @return {Promise}
4337
+ * @typedef {this & {then: null}} ResolvedTimeline
4338
+ */
4339
+
4340
+ /**
4341
+ * @param {Callback<ResolvedTimeline>} [callback]
4342
+ * @return Promise<this>
4409
4343
  */
4410
4344
  then(callback) {
4411
4345
  return super.then(callback);
@@ -4515,7 +4449,7 @@ class Animatable {
4515
4449
  tween._currentTime = 0;
4516
4450
  });
4517
4451
  if (!isUnd(duration)) animation.stretch(duration);
4518
- animation.reset(1).resume();
4452
+ animation.reset(true).resume();
4519
4453
  return this;
4520
4454
  }
4521
4455
  };
@@ -4633,8 +4567,10 @@ var numberImports = /*#__PURE__*/Object.freeze({
4633
4567
 
4634
4568
 
4635
4569
 
4570
+
4571
+
4636
4572
  /*
4637
- * Spring ease solver adapted from https://webkit.org/demos/spring/spring.js
4573
+ * Spring easing solver adapted from https://webkit.org/demos/spring/spring.js
4638
4574
  * (c) 2016 Webkit - Apple Inc
4639
4575
  */
4640
4576
 
@@ -4645,25 +4581,46 @@ class Spring {
4645
4581
  * @param {SpringParams} [parameters]
4646
4582
  */
4647
4583
  constructor(parameters = {}) {
4584
+ const hasBounceOrDuration = !isUnd(parameters.bounce) || !isUnd(parameters.duration);
4648
4585
  this.timeStep = .02; // Interval fed to the solver to calculate duration
4649
4586
  this.restThreshold = .0005; // Values below this threshold are considered resting position
4650
4587
  this.restDuration = 200; // Duration in ms used to check if the spring is resting after reaching restThreshold
4651
4588
  this.maxDuration = 60000; // The maximum allowed spring duration in ms (default 1 min)
4652
4589
  this.maxRestSteps = this.restDuration / this.timeStep / K; // How many steps allowed after reaching restThreshold before stopping the duration calculation
4653
4590
  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);
4591
+ this.bn = clamp$1(setValue(parameters.bounce, .5), -1, 1); // The bounce percentage between -1 and 1.
4592
+ this.pd = clamp$1(setValue(parameters.duration, 628), 10 * globals.timeScale, maxSpringParamValue * globals.timeScale); // The perceived duration
4593
+ this.m = clamp$1(setValue(parameters.mass, 1), 1, maxSpringParamValue);
4594
+ this.s = clamp$1(setValue(parameters.stiffness, 100), minValue, maxSpringParamValue);
4595
+ this.d = clamp$1(setValue(parameters.damping, 10), minValue, maxSpringParamValue);
4657
4596
  this.v = clamp$1(setValue(parameters.velocity, 0), -maxSpringParamValue, maxSpringParamValue);
4658
4597
  this.w0 = 0;
4659
4598
  this.zeta = 0;
4660
4599
  this.wd = 0;
4661
4600
  this.b = 0;
4601
+ this.completed = false;
4662
4602
  this.solverDuration = 0;
4663
- this.duration = 0;
4603
+ this.settlingDuration = 0;
4604
+ /** @type {JSAnimation} */
4605
+ this.parent = null;
4606
+ /** @type {Callback<JSAnimation>} */
4607
+ this.onComplete = parameters.onComplete || noop;
4608
+ if (hasBounceOrDuration) this.calculateSDFromBD();
4664
4609
  this.compute();
4665
4610
  /** @type {EasingFunction} */
4666
- this.ease = t => t === 0 || t === 1 ? t : this.solve(t * this.solverDuration);
4611
+ this.ease = t => {
4612
+ const currentTime = t * this.settlingDuration;
4613
+ const completed = this.completed;
4614
+ const perceivedTime = this.pd;
4615
+ if (currentTime >= perceivedTime && !completed) {
4616
+ this.completed = true;
4617
+ this.onComplete(this.parent);
4618
+ }
4619
+ if (currentTime < perceivedTime && completed) {
4620
+ this.completed = false;
4621
+ }
4622
+ return t === 0 || t === 1 ? t : this.solve(t * this.solverDuration);
4623
+ };
4667
4624
  }
4668
4625
 
4669
4626
  /** @type {EasingFunction} */
@@ -4671,23 +4628,83 @@ class Spring {
4671
4628
  const { zeta, w0, wd, b } = this;
4672
4629
  let t = time;
4673
4630
  if (zeta < 1) {
4631
+ // Underdamped
4674
4632
  t = exp(-t * zeta * w0) * (1 * cos(wd * t) + b * sin(wd * t));
4675
- } else {
4633
+ } else if (zeta === 1) {
4634
+ // Critically damped
4676
4635
  t = (1 + b * t) * exp(-t * w0);
4636
+ } else {
4637
+ // Overdamped
4638
+ // Using exponential instead of cosh and sinh functions to prevent Infinity
4639
+ // Original exp(-zeta * w0 * t) * (cosh(wd * t) + b * sinh(wd * t))
4640
+ t = ((1 + b) * exp((-zeta * w0 + wd) * t) + (1 - b) * exp((-zeta * w0 - wd) * t)) / 2;
4677
4641
  }
4678
4642
  return 1 - t;
4679
4643
  }
4680
4644
 
4645
+ calculateSDFromBD() {
4646
+ // Apple's SwiftUI perceived spring duration implementation https://developer.apple.com/videos/play/wwdc2023/10158/?time=1010
4647
+ // Equations taken from Kevin Grajeda's article https://www.kvin.me/posts/effortless-ui-spring-animations
4648
+ const pds = globals.timeScale === 1 ? this.pd / K : this.pd;
4649
+ // Mass and velocity should be set to their default values
4650
+ this.m = 1;
4651
+ this.v = 0;
4652
+ // Stiffness = (2π ÷ perceptualDuration)²
4653
+ this.s = pow((2 * PI) / pds, 2);
4654
+ if (this.bn >= 0) {
4655
+ // For bounce ≥ 0 (critically damped to underdamped)
4656
+ // damping = ((1 - bounce) × 4π) ÷ perceptualDuration
4657
+ this.d = ((1 - this.bn) * 4 * PI) / pds;
4658
+ } else {
4659
+ // For bounce < 0 (overdamped)
4660
+ // damping = 4π ÷ (perceptualDuration × (1 + bounce))
4661
+ // Note: (1 + bounce) is positive since bounce is negative
4662
+ this.d = (4 * PI) / (pds * (1 + this.bn));
4663
+ }
4664
+ this.s = round$1(clamp$1(this.s, minValue, maxSpringParamValue), 3);
4665
+ this.d = round$1(clamp$1(this.d, minValue, 300), 3); // Clamping to 300 is needed to prevent insane values in the solver
4666
+ }
4667
+
4668
+ calculateBDFromSD() {
4669
+ // Calculate perceived duration and bounce from stiffness and damping
4670
+ // Note: We assumes m = 1 and v = 0 for these calculations
4671
+ const pds = (2 * PI) / sqrt(this.s);
4672
+ this.pd = pds * (globals.timeScale === 1 ? K : 1);
4673
+ const zeta = this.d / (2 * sqrt(this.s));
4674
+ if (zeta <= 1) {
4675
+ // Critically damped to underdamped
4676
+ this.bn = 1 - (this.d * pds) / (4 * PI);
4677
+ } else {
4678
+ // Overdamped
4679
+ this.bn = (4 * PI) / (this.d * pds) - 1;
4680
+ }
4681
+ this.bn = round$1(clamp$1(this.bn, -1, 1), 3);
4682
+ this.pd = round$1(clamp$1(this.pd, 10 * globals.timeScale, maxSpringParamValue * globals.timeScale), 3);
4683
+ }
4684
+
4681
4685
  compute() {
4682
4686
  const { maxRestSteps, maxIterations, restThreshold, timeStep, m, d, s, v } = this;
4683
4687
  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;
4688
+ const bouncedZeta = this.zeta = d / (2 * sqrt(s * m));
4689
+ // Calculate wd based on damping type
4690
+ if (bouncedZeta < 1) {
4691
+ // Underdamped
4692
+ this.wd = w0 * sqrt(1 - bouncedZeta * bouncedZeta);
4693
+ this.b = (bouncedZeta * w0 + -v) / this.wd;
4694
+ } else if (bouncedZeta === 1) {
4695
+ // Critically damped
4696
+ this.wd = 0;
4697
+ this.b = -v + w0;
4698
+ } else {
4699
+ // Overdamped
4700
+ this.wd = w0 * sqrt(bouncedZeta * bouncedZeta - 1);
4701
+ this.b = (bouncedZeta * w0 + -v) / this.wd;
4702
+ }
4703
+
4687
4704
  let solverTime = 0;
4688
4705
  let restSteps = 0;
4689
4706
  let iterations = 0;
4690
- while (restSteps < maxRestSteps && iterations < maxIterations) {
4707
+ while (restSteps <= maxRestSteps && iterations <= maxIterations) {
4691
4708
  if (abs(1 - this.solve(solverTime)) < restThreshold) {
4692
4709
  restSteps++;
4693
4710
  } else {
@@ -4697,15 +4714,26 @@ class Spring {
4697
4714
  solverTime += timeStep;
4698
4715
  iterations++;
4699
4716
  }
4700
- this.duration = round$1(this.solverDuration * K, 0) * globals.timeScale;
4717
+ this.settlingDuration = round$1(this.solverDuration * K, 0) * globals.timeScale;
4701
4718
  }
4702
4719
 
4703
- get mass() {
4704
- return this.m;
4720
+ get bounce() {
4721
+ return this.bn;
4705
4722
  }
4706
4723
 
4707
- set mass(v) {
4708
- this.m = clamp$1(setValue(v, 1), 0, maxSpringParamValue);
4724
+ set bounce(v) {
4725
+ this.bn = clamp$1(setValue(v, 1), -1, 1);
4726
+ this.calculateSDFromBD();
4727
+ this.compute();
4728
+ }
4729
+
4730
+ get duration() {
4731
+ return this.pd;
4732
+ }
4733
+
4734
+ set duration(v) {
4735
+ this.pd = clamp$1(setValue(v, 1), 10 * globals.timeScale, maxSpringParamValue * globals.timeScale);
4736
+ this.calculateSDFromBD();
4709
4737
  this.compute();
4710
4738
  }
4711
4739
 
@@ -4714,7 +4742,8 @@ class Spring {
4714
4742
  }
4715
4743
 
4716
4744
  set stiffness(v) {
4717
- this.s = clamp$1(setValue(v, 100), 1, maxSpringParamValue);
4745
+ this.s = clamp$1(setValue(v, 100), minValue, maxSpringParamValue);
4746
+ this.calculateBDFromSD();
4718
4747
  this.compute();
4719
4748
  }
4720
4749
 
@@ -4723,7 +4752,17 @@ class Spring {
4723
4752
  }
4724
4753
 
4725
4754
  set damping(v) {
4726
- this.d = clamp$1(setValue(v, 10), .1, maxSpringParamValue);
4755
+ this.d = clamp$1(setValue(v, 10), minValue, maxSpringParamValue);
4756
+ this.calculateBDFromSD();
4757
+ this.compute();
4758
+ }
4759
+
4760
+ get mass() {
4761
+ return this.m;
4762
+ }
4763
+
4764
+ set mass(v) {
4765
+ this.m = clamp$1(setValue(v, 1), 1, maxSpringParamValue);
4727
4766
  this.compute();
4728
4767
  }
4729
4768
 
@@ -4741,7 +4780,18 @@ class Spring {
4741
4780
  * @param {SpringParams} [parameters]
4742
4781
  * @returns {Spring}
4743
4782
  */
4744
- const createSpring = (parameters) => new Spring(parameters);
4783
+ const spring = (parameters) => new Spring(parameters);
4784
+
4785
+ /**
4786
+ * @deprecated createSpring() is deprecated use spring() instead
4787
+ *
4788
+ * @param {SpringParams} [parameters]
4789
+ * @returns {Spring}
4790
+ */
4791
+ const createSpring = (parameters) => {
4792
+ console.warn('createSpring() is deprecated use spring() instead');
4793
+ return new Spring(parameters);
4794
+ };
4745
4795
 
4746
4796
 
4747
4797
 
@@ -4860,7 +4910,7 @@ class Transforms {
4860
4910
  }
4861
4911
 
4862
4912
  /**
4863
- * @template {Array<Number>|DOMTargetSelector|String|Number|Boolean|Function|DraggableCursorParams} T
4913
+ * @template {Array<Number>|DOMTargetSelector|String|Number|Boolean|Function|DraggableCursorParams|DraggableDragThresholdParams} T
4864
4914
  * @param {T | ((draggable: Draggable) => T)} value
4865
4915
  * @param {Draggable} draggable
4866
4916
  * @return {T}
@@ -4914,6 +4964,8 @@ class Draggable {
4914
4964
  /** @type {Number} */
4915
4965
  this.dragSpeed = 0;
4916
4966
  /** @type {Number} */
4967
+ this.dragThreshold = 3;
4968
+ /** @type {Number} */
4917
4969
  this.maxVelocity = 0;
4918
4970
  /** @type {Number} */
4919
4971
  this.minVelocity = 0;
@@ -4922,13 +4974,13 @@ class Draggable {
4922
4974
  /** @type {Boolean|DraggableCursorParams} */
4923
4975
  this.cursor = false;
4924
4976
  /** @type {Spring} */
4925
- this.releaseXSpring = hasSpring ? /** @type {Spring} */(ease) : createSpring({
4977
+ this.releaseXSpring = hasSpring ? /** @type {Spring} */(ease) : spring({
4926
4978
  mass: setValue(parameters.releaseMass, 1),
4927
4979
  stiffness: setValue(parameters.releaseStiffness, 80),
4928
4980
  damping: setValue(parameters.releaseDamping, 20),
4929
4981
  });
4930
4982
  /** @type {Spring} */
4931
- this.releaseYSpring = hasSpring ? /** @type {Spring} */(ease) : createSpring({
4983
+ this.releaseYSpring = hasSpring ? /** @type {Spring} */(ease) : spring({
4932
4984
  mass: setValue(parameters.releaseMass, 1),
4933
4985
  stiffness: setValue(parameters.releaseStiffness, 80),
4934
4986
  damping: setValue(parameters.releaseDamping, 20),
@@ -5331,6 +5383,16 @@ class Draggable {
5331
5383
  if (onHover) cursorStyles.onHover = onHover;
5332
5384
  if (onGrab) cursorStyles.onGrab = onGrab;
5333
5385
  }
5386
+ const parsedDragThreshold = parseDraggableFunctionParameter(params.dragThreshold, this);
5387
+ const dragThreshold = { mouse: 3, touch: 7 };
5388
+ if (isNum(parsedDragThreshold)) {
5389
+ dragThreshold.mouse = parsedDragThreshold;
5390
+ dragThreshold.touch = parsedDragThreshold;
5391
+ } else if (parsedDragThreshold) {
5392
+ const { mouse, touch } = parsedDragThreshold;
5393
+ if (!isUnd(mouse)) dragThreshold.mouse = mouse;
5394
+ if (!isUnd(touch)) dragThreshold.touch = touch;
5395
+ }
5334
5396
  this.containerArray = isArr(container) ? container : null;
5335
5397
  this.$container = /** @type {HTMLElement} */(container && !this.containerArray ? parseTargets(/** @type {DOMTarget} */(container))[0] : doc.body);
5336
5398
  this.useWin = this.$container === doc.body;
@@ -5345,6 +5407,7 @@ class Draggable {
5345
5407
  this.scrollSpeed = setValue(parseDraggableFunctionParameter(params.scrollSpeed, this), 1.5);
5346
5408
  this.scrollThreshold = setValue(parseDraggableFunctionParameter(params.scrollThreshold, this), 20);
5347
5409
  this.dragSpeed = setValue(parseDraggableFunctionParameter(params.dragSpeed, this), 1);
5410
+ this.dragThreshold = this.isFinePointer ? dragThreshold.mouse : dragThreshold.touch;
5348
5411
  this.minVelocity = setValue(parseDraggableFunctionParameter(params.minVelocity, this), 0);
5349
5412
  this.maxVelocity = setValue(parseDraggableFunctionParameter(params.maxVelocity, this), 50);
5350
5413
  this.velocityMultiplier = setValue(parseDraggableFunctionParameter(params.velocityMultiplier, this), 1);
@@ -5645,9 +5708,8 @@ class Draggable {
5645
5708
  this.$trigger.addEventListener('touchmove', preventDefault, { passive: false });
5646
5709
  this.$trigger.addEventListener('touchend', preventDefault);
5647
5710
 
5648
-
5649
- if ((!this.disabled[0] && abs(movedX) > 3) || (!this.disabled[1] && abs(movedY) > 3)) {
5650
-
5711
+ // Don't check for a miminim distance move if already dragging
5712
+ if (this.dragged || (!this.disabled[0] && abs(movedX) > this.dragThreshold) || (!this.disabled[1] && abs(movedY) > this.dragThreshold)) {
5651
5713
  this.updateTicker.resume();
5652
5714
  this.pointer[2] = this.pointer[0];
5653
5715
  this.pointer[3] = this.pointer[1];
@@ -5712,8 +5774,8 @@ class Draggable {
5712
5774
  const directionX = dx === cr ? cx > cr ? -1 : 1 : cx < cl ? -1 : 1;
5713
5775
  const distanceX = round$1(cx - dx, 0);
5714
5776
  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);
5777
+ const { ease, settlingDuration, restDuration } = springX;
5778
+ durationX = cx === dx ? 0 : hasReleaseSpring ? settlingDuration : settlingDuration - (restDuration * globals.timeScale);
5717
5779
  if (hasReleaseSpring) easeX = ease;
5718
5780
  if (durationX > longestReleaseDuration) longestReleaseDuration = durationX;
5719
5781
  }
@@ -5722,8 +5784,8 @@ class Draggable {
5722
5784
  const directionY = dy === cb ? cy > cb ? -1 : 1 : cy < ct ? -1 : 1;
5723
5785
  const distanceY = round$1(cy - dy, 0);
5724
5786
  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);
5787
+ const { ease, settlingDuration, restDuration } = springY;
5788
+ durationY = cy === dy ? 0 : hasReleaseSpring ? settlingDuration : settlingDuration - (restDuration * globals.timeScale);
5727
5789
  if (hasReleaseSpring) easeY = ease;
5728
5790
  if (durationY > longestReleaseDuration) longestReleaseDuration = durationY;
5729
5791
  }
@@ -6236,6 +6298,8 @@ class ScrollContainer {
6236
6298
  /** @type {Number} */
6237
6299
  this.top = 0;
6238
6300
  /** @type {Number} */
6301
+ this.scale = 1;
6302
+ /** @type {Number} */
6239
6303
  this.zIndex = 0;
6240
6304
  /** @type {Number} */
6241
6305
  this.scrollX = 0;
@@ -6347,6 +6411,7 @@ class ScrollContainer {
6347
6411
  height = $el.clientHeight;
6348
6412
  this.top = elRect.top;
6349
6413
  this.left = elRect.left;
6414
+ this.scale = elRect.width ? width / elRect.width : (elRect.height ? height / elRect.height : 1);
6350
6415
  }
6351
6416
  this.width = width;
6352
6417
  this.height = height;
@@ -6576,6 +6641,8 @@ class ScrollObserver {
6576
6641
  /** @type {Boolean} */
6577
6642
  this.reverted = false;
6578
6643
  /** @type {Boolean} */
6644
+ this.ready = false;
6645
+ /** @type {Boolean} */
6579
6646
  this.completed = false;
6580
6647
  /** @type {Boolean} */
6581
6648
  this.began = false;
@@ -6585,8 +6652,6 @@ class ScrollObserver {
6585
6652
  this.forceEnter = false;
6586
6653
  /** @type {Boolean} */
6587
6654
  this.hasEntered = false;
6588
- // /** @type {Array.<Number>} */
6589
- // this.offsets = [];
6590
6655
  /** @type {Number} */
6591
6656
  this.offset = 0;
6592
6657
  /** @type {Number} */
@@ -6634,6 +6699,8 @@ class ScrollObserver {
6634
6699
  // Make sure to pause the linked object in case it's added later
6635
6700
  linked.pause();
6636
6701
  this.linked = linked;
6702
+ // Forces WAAPI Animation to persist; otherwise, they will stop syncing on finish.
6703
+ if (!isUnd(/** @type {WAAPIAnimation} */(linked))) /** @type {WAAPIAnimation} */(linked).persist = true;
6637
6704
  // Try to use a target of the linked object if no target parameters specified
6638
6705
  if (!this._params.target) {
6639
6706
  /** @type {HTMLElement} */
@@ -6673,6 +6740,8 @@ class ScrollObserver {
6673
6740
  }
6674
6741
 
6675
6742
  refresh() {
6743
+ // This flag is used to prevent running handleScroll() outside of this.refresh() with values not yet calculated
6744
+ this.ready = true;
6676
6745
  this.reverted = false;
6677
6746
  const params = this._params;
6678
6747
  this.repeat = setValue(parseScrollObserverFunctionParameter(params.repeat, this), true);
@@ -6868,8 +6937,9 @@ class ScrollObserver {
6868
6937
  }
6869
6938
  }
6870
6939
  const rect = $target.getBoundingClientRect();
6871
- const offset = isHori ? rect.left + container.scrollX - container.left : rect.top + container.scrollY - container.top;
6872
- const targetSize = isHori ? rect.width : rect.height;
6940
+ const scale = container.scale;
6941
+ const offset = (isHori ? rect.left + container.scrollX - container.left : rect.top + container.scrollY - container.top) * scale;
6942
+ const targetSize = (isHori ? rect.width : rect.height) * scale;
6873
6943
  const containerSize = isHori ? container.width : container.height;
6874
6944
  const scrollSize = isHori ? container.scrollWidth : container.scrollHeight;
6875
6945
  const maxScroll = scrollSize - containerSize;
@@ -6918,8 +6988,6 @@ class ScrollObserver {
6918
6988
  const offsetStart = parsedEnterTarget + offset - parsedEnterContainer;
6919
6989
  const offsetEnd = parsedLeaveTarget + offset - parsedLeaveContainer;
6920
6990
  const scrollDelta = offsetEnd - offsetStart;
6921
- // this.offsets[0] = offsetX;
6922
- // this.offsets[1] = offsetY;
6923
6991
  this.offset = offset;
6924
6992
  this.offsetStart = offsetStart;
6925
6993
  this.offsetEnd = offsetEnd;
@@ -6938,6 +7006,7 @@ class ScrollObserver {
6938
7006
  }
6939
7007
 
6940
7008
  handleScroll() {
7009
+ if (!this.ready) return;
6941
7010
  const linked = this.linked;
6942
7011
  const sync = this.sync;
6943
7012
  const syncEase = this.syncEase;
@@ -7061,6 +7130,7 @@ class ScrollObserver {
7061
7130
  this.removeDebug();
7062
7131
  }
7063
7132
  this.reverted = true;
7133
+ this.ready = false;
7064
7134
  return this;
7065
7135
  }
7066
7136
 
@@ -7072,13 +7142,142 @@ class ScrollObserver {
7072
7142
  */
7073
7143
  const onScroll = (parameters = {}) => new ScrollObserver(parameters);
7074
7144
 
7145
+
7146
+
7147
+ /**
7148
+ * Cubic Bezier solver adapted from https://github.com/gre/bezier-easing
7149
+ * (c) 2014 Gaëtan Renaudeau
7150
+ */
7151
+
7152
+ /**
7153
+ * @param {Number} aT
7154
+ * @param {Number} aA1
7155
+ * @param {Number} aA2
7156
+ * @return {Number}
7157
+ */
7158
+ const calcBezier = (aT, aA1, aA2) => (((1 - 3 * aA2 + 3 * aA1) * aT + (3 * aA2 - 6 * aA1)) * aT + (3 * aA1)) * aT;
7159
+
7160
+ /**
7161
+ * @param {Number} aX
7162
+ * @param {Number} mX1
7163
+ * @param {Number} mX2
7164
+ * @return {Number}
7165
+ */
7166
+ const binarySubdivide = (aX, mX1, mX2) => {
7167
+ let aA = 0, aB = 1, currentX, currentT, i = 0;
7168
+ do {
7169
+ currentT = aA + (aB - aA) / 2;
7170
+ currentX = calcBezier(currentT, mX1, mX2) - aX;
7171
+ if (currentX > 0) {
7172
+ aB = currentT;
7173
+ } else {
7174
+ aA = currentT;
7175
+ }
7176
+ } while (abs(currentX) > .0000001 && ++i < 100);
7177
+ return currentT;
7178
+ };
7179
+
7180
+ /**
7181
+ * @param {Number} [mX1] The x coordinate of the first point
7182
+ * @param {Number} [mY1] The y coordinate of the first point
7183
+ * @param {Number} [mX2] The x coordinate of the second point
7184
+ * @param {Number} [mY2] The y coordinate of the second point
7185
+ * @return {EasingFunction}
7186
+ */
7187
+
7188
+ const cubicBezier = (mX1 = 0.5, mY1 = 0.0, mX2 = 0.5, mY2 = 1.0) => (mX1 === mY1 && mX2 === mY2) ? none :
7189
+ t => t === 0 || t === 1 ? t :
7190
+ calcBezier(binarySubdivide(t, mX1, mX2), mY1, mY2);
7191
+
7192
+
7193
+
7194
+ /**
7195
+ * Steps ease implementation https://developer.mozilla.org/fr/docs/Web/CSS/transition-timing-function
7196
+ * Only covers 'end' and 'start' jumpterms
7197
+ * @param {Number} steps
7198
+ * @param {Boolean} [fromStart]
7199
+ * @return {EasingFunction}
7200
+ */
7201
+ const steps = (steps = 10, fromStart) => {
7202
+ const roundMethod = fromStart ? ceil : floor;
7203
+ return t => roundMethod(clamp$1(t, 0, 1) * steps) * (1 / steps);
7204
+ };
7205
+
7206
+
7207
+
7208
+ /**
7209
+ * Without parameters, the linear function creates a non-eased transition.
7210
+ * Parameters, if used, creates a piecewise linear easing by interpolating linearly between the specified points.
7211
+ *
7212
+ * @param {...(String|Number)} args - Points
7213
+ * @return {EasingFunction}
7214
+ */
7215
+ const linear = (...args) => {
7216
+ const argsLength = args.length;
7217
+ if (!argsLength) return none;
7218
+ const totalPoints = argsLength - 1;
7219
+ const firstArg = args[0];
7220
+ const lastArg = args[totalPoints];
7221
+ const xPoints = [0];
7222
+ const yPoints = [parseNumber(firstArg)];
7223
+ for (let i = 1; i < totalPoints; i++) {
7224
+ const arg = args[i];
7225
+ const splitValue = isStr(arg) ?
7226
+ /** @type {String} */(arg).trim().split(' ') :
7227
+ [arg];
7228
+ const value = splitValue[0];
7229
+ const percent = splitValue[1];
7230
+ xPoints.push(!isUnd(percent) ? parseNumber(percent) / 100 : i / totalPoints);
7231
+ yPoints.push(parseNumber(value));
7232
+ }
7233
+ yPoints.push(parseNumber(lastArg));
7234
+ xPoints.push(1);
7235
+ return function easeLinear(t) {
7236
+ for (let i = 1, l = xPoints.length; i < l; i++) {
7237
+ const currentX = xPoints[i];
7238
+ if (t <= currentX) {
7239
+ const prevX = xPoints[i - 1];
7240
+ const prevY = yPoints[i - 1];
7241
+ return prevY + (yPoints[i] - prevY) * (t - prevX) / (currentX - prevX);
7242
+ }
7243
+ }
7244
+ return yPoints[yPoints.length - 1];
7245
+ }
7246
+ };
7247
+
7248
+
7249
+
7250
+ /**
7251
+ * Generate random steps
7252
+ * @param {Number} [length] - The number of steps
7253
+ * @param {Number} [randomness] - How strong the randomness is
7254
+ * @return {EasingFunction}
7255
+ */
7256
+ const irregular = (length = 10, randomness = 1) => {
7257
+ const values = [0];
7258
+ const total = length - 1;
7259
+ for (let i = 1; i < total; i++) {
7260
+ const previousValue = values[i - 1];
7261
+ const spacing = i / total;
7262
+ const segmentEnd = (i + 1) / total;
7263
+ const randomVariation = spacing + (segmentEnd - spacing) * Math.random();
7264
+ // Mix the even spacing and random variation based on the randomness parameter
7265
+ const randomValue = spacing * (1 - randomness) + randomVariation * randomness;
7266
+ values.push(clamp$1(randomValue, previousValue, 1));
7267
+ }
7268
+ values.push(1);
7269
+ return linear(...values);
7270
+ };
7271
+
7075
7272
  var index$3 = /*#__PURE__*/Object.freeze({
7076
7273
  __proto__: null,
7274
+ Spring: Spring,
7275
+ createSpring: createSpring,
7077
7276
  cubicBezier: cubicBezier,
7078
7277
  eases: eases,
7079
7278
  irregular: irregular,
7080
7279
  linear: linear,
7081
- none: none,
7280
+ spring: spring,
7082
7281
  steps: steps
7083
7282
  });
7084
7283
 
@@ -7454,20 +7653,24 @@ const getPath = path => {
7454
7653
 
7455
7654
  /**
7456
7655
  * @param {SVGGeometryElement} $path
7656
+ * @param {Number} totalLength
7457
7657
  * @param {Number} progress
7458
7658
  * @param {Number}lookup
7459
7659
  * @return {DOMPoint}
7460
7660
  */
7461
- const getPathPoint = ($path, progress, lookup = 0) => {
7462
- return $path.getPointAtLength(progress + lookup >= 1 ? progress + lookup : 0);
7661
+ const getPathPoint = ($path, totalLength, progress, lookup = 0) => {
7662
+ const point = progress + lookup;
7663
+ const pointOnPath = (point % totalLength + totalLength) % totalLength;
7664
+ return $path.getPointAtLength(pointOnPath);
7463
7665
  };
7464
7666
 
7465
7667
  /**
7466
7668
  * @param {SVGGeometryElement} $path
7467
7669
  * @param {String} pathProperty
7670
+ * @param {Number} [offset=0]
7468
7671
  * @return {FunctionValue}
7469
7672
  */
7470
- const getPathProgess = ($path, pathProperty) => {
7673
+ const getPathProgess = ($path, pathProperty, offset = 0) => {
7471
7674
  return $el => {
7472
7675
  const totalLength = +($path.getTotalLength());
7473
7676
  const inSvg = $el[isSvgSymbol];
@@ -7478,12 +7681,14 @@ const getPathProgess = ($path, pathProperty) => {
7478
7681
  to: totalLength,
7479
7682
  /** @type {TweenModifier} */
7480
7683
  modifier: progress => {
7684
+ const offsetLength = offset * totalLength;
7685
+ const newProgress = progress + offsetLength;
7481
7686
  if (pathProperty === 'a') {
7482
- const p0 = getPathPoint($path, progress, -1);
7483
- const p1 = getPathPoint($path, progress, 1);
7687
+ const p0 = getPathPoint($path, totalLength, newProgress, -1);
7688
+ const p1 = getPathPoint($path, totalLength, newProgress, 1);
7484
7689
  return atan2(p1.y - p0.y, p1.x - p0.x) * 180 / PI;
7485
7690
  } else {
7486
- const p = getPathPoint($path, progress, 0);
7691
+ const p = getPathPoint($path, totalLength, newProgress, 0);
7487
7692
  return pathProperty === 'x' ?
7488
7693
  inSvg || !ctm ? p.x : p.x * ctm.a + p.y * ctm.c + ctm.e :
7489
7694
  inSvg || !ctm ? p.y : p.x * ctm.b + p.y * ctm.d + ctm.f
@@ -7495,14 +7700,15 @@ const getPathProgess = ($path, pathProperty) => {
7495
7700
 
7496
7701
  /**
7497
7702
  * @param {TargetsParam} path
7703
+ * @param {Number} [offset=0]
7498
7704
  */
7499
- const createMotionPath = path => {
7705
+ const createMotionPath = (path, offset = 0) => {
7500
7706
  const $path = getPath(path);
7501
7707
  if (!$path) return;
7502
7708
  return {
7503
- translateX: getPathProgess($path, 'x'),
7504
- translateY: getPathProgess($path, 'y'),
7505
- rotate: getPathProgess($path, 'a'),
7709
+ translateX: getPathProgess($path, 'x', offset),
7710
+ translateY: getPathProgess($path, 'y', offset),
7711
+ rotate: getPathProgess($path, 'a', offset),
7506
7712
  }
7507
7713
  };
7508
7714
 
@@ -7614,8 +7820,18 @@ const createDrawable = (selector, start = 0, end = 0) => {
7614
7820
  * @return {FunctionValue}
7615
7821
  */
7616
7822
  const morphTo = (path2, precision = .33) => ($path1) => {
7823
+ const tagName1 = ($path1.tagName || '').toLowerCase();
7824
+ if (!tagName1.match(/^(path|polygon|polyline)$/)) {
7825
+ throw new Error(`Can't morph a <${$path1.tagName}> SVG element. Use <path>, <polygon> or <polyline>.`);
7826
+ }
7617
7827
  const $path2 = /** @type {SVGGeometryElement} */(getPath(path2));
7618
- if (!$path2) return;
7828
+ if (!$path2) {
7829
+ throw new Error("Can't morph to an invalid target. 'path2' must resolve to an existing <path>, <polygon> or <polyline> SVG element.");
7830
+ }
7831
+ const tagName2 = ($path2.tagName || '').toLowerCase();
7832
+ if (!tagName2.match(/^(path|polygon|polyline)$/)) {
7833
+ throw new Error(`Can't morph a <${$path2.tagName}> SVG element. Use <path>, <polygon> or <polyline>.`);
7834
+ }
7619
7835
  const isPath = $path1.tagName === 'path';
7620
7836
  const separator = isPath ? ' ' : ',';
7621
7837
  const previousPoints = $path1[morphPointsSymbol];
@@ -8134,21 +8350,11 @@ var index = /*#__PURE__*/Object.freeze({
8134
8350
  */
8135
8351
  const easingToLinear = (fn, samples = 100) => {
8136
8352
  const points = [];
8137
- for (let i = 0; i <= samples; i++) points.push(fn(i / samples));
8353
+ for (let i = 0; i <= samples; i++) points.push(round$1(fn(i / samples), 4));
8138
8354
  return `linear(${points.join(', ')})`;
8139
8355
  };
8140
8356
 
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
- })();
8357
+ const WAAPIEasesLookups = {};
8152
8358
 
8153
8359
  /**
8154
8360
  * @param {EasingParam} ease
@@ -8169,9 +8375,10 @@ const parseWAAPIEasing = (ease) => {
8169
8375
  } else if (stringStartsWith(ease, 'cubicB')) {
8170
8376
  parsedEase = toLowerCase(ease);
8171
8377
  } else {
8172
- const parsed = parseEaseString(ease, WAAPIeases, WAAPIEasesLookups);
8378
+ const parsed = parseEaseString(ease);
8173
8379
  if (isFnc(parsed)) parsedEase = parsed === none ? 'linear' : easingToLinear(parsed);
8174
8380
  }
8381
+ // Only cache string based easing name, otherwise function arguments get lost
8175
8382
  WAAPIEasesLookups[ease] = parsedEase;
8176
8383
  } else if (isFnc(ease)) {
8177
8384
  const easing = easingToLinear(ease);
@@ -8212,7 +8419,8 @@ let transformsPropertiesRegistered = null;
8212
8419
  * @return {String}
8213
8420
  */
8214
8421
  const normalizeTweenValue = (propName, value, $el, i, targetsLength) => {
8215
- let v = getFunctionValue(/** @type {any} */(value), $el, i, targetsLength);
8422
+ // Do not try to compute strings with getFunctionValue otherwise it will convert CSS variables
8423
+ let v = isStr(value) ? value : getFunctionValue(/** @type {any} */(value), $el, i, targetsLength);
8216
8424
  if (!isNum(v)) return v;
8217
8425
  if (commonDefaultPXProperties.includes(propName) || stringStartsWith(propName, 'translate')) return `${v}px`;
8218
8426
  if (stringStartsWith(propName, 'rotate') || stringStartsWith(propName, 'skew')) return `${v}deg`;
@@ -8292,7 +8500,7 @@ class WAAPIAnimation {
8292
8500
  /** @type {PlaybackDirection} */
8293
8501
  const direction = alternate ? reversed ? 'alternate-reverse' : 'alternate' : reversed ? 'reverse' : 'normal';
8294
8502
  /** @type {FillMode} */
8295
- const fill = 'forwards';
8503
+ const fill = 'both'; // We use 'both' here because the animation can be reversed during playback
8296
8504
  /** @type {String} */
8297
8505
  const easing = parseWAAPIEasing(ease);
8298
8506
  const timeScale = (globals.timeScale === 1 ? 1 : K);
@@ -8304,7 +8512,7 @@ class WAAPIAnimation {
8304
8512
  /** @type {globalThis.Animation}] */
8305
8513
  this.controlAnimation = null;
8306
8514
  /** @type {Callback<this>} */
8307
- this.onComplete = params.onComplete || noop;
8515
+ this.onComplete = params.onComplete || /** @type {Callback<WAAPIAnimation>} */(/** @type {unknown} */(globals.defaults.onComplete));
8308
8516
  /** @type {Number} */
8309
8517
  this.duration = 0;
8310
8518
  /** @type {Boolean} */
@@ -8315,6 +8523,8 @@ class WAAPIAnimation {
8315
8523
  this.paused = !autoplay || scroll !== false;
8316
8524
  /** @type {Boolean} */
8317
8525
  this.reversed = reversed;
8526
+ /** @type {Boolean} */
8527
+ this.persist = setValue(params.persist, globals.defaults.persist);
8318
8528
  /** @type {Boolean|ScrollObserver} */
8319
8529
  this.autoplay = autoplay;
8320
8530
  /** @type {Number} */
@@ -8323,17 +8533,18 @@ class WAAPIAnimation {
8323
8533
  this._resolve = noop; // Used by .then()
8324
8534
  /** @type {Number} */
8325
8535
  this._completed = 0;
8326
- /** @type {Array<Object>}] */
8327
- this._inlineStyles = parsedTargets.map($el => $el.getAttribute('style'));
8536
+ /** @type {Array.<Object>} */
8537
+ this._inlineStyles = [];
8328
8538
 
8329
8539
  parsedTargets.forEach(($el, i) => {
8330
8540
 
8331
8541
  const cachedTransforms = $el[transformsSymbol];
8332
-
8333
8542
  const hasIndividualTransforms = validIndividualTransforms.some(t => params.hasOwnProperty(t));
8543
+ const elStyle = $el.style;
8544
+ const inlineStyles = this._inlineStyles[i] = {};
8334
8545
 
8335
8546
  /** @type {Number} */
8336
- const duration = (spring ? /** @type {Spring} */(spring).duration : getFunctionValue(setValue(params.duration, globals.defaults.duration), $el, i, targetsLength)) * timeScale;
8547
+ const duration = (spring ? /** @type {Spring} */(spring).settlingDuration : getFunctionValue(setValue(params.duration, globals.defaults.duration), $el, i, targetsLength)) * timeScale;
8337
8548
  /** @type {Number} */
8338
8549
  const delay = getFunctionValue(setValue(params.delay, globals.defaults.delay), $el, i, targetsLength) * timeScale;
8339
8550
  /** @type {CompositeOperation} */
@@ -8347,6 +8558,12 @@ class WAAPIAnimation {
8347
8558
  const tweenParams = { iterations, direction, fill, easing, duration, delay, composite };
8348
8559
  const propertyValue = params[name];
8349
8560
  const individualTransformProperty = hasIndividualTransforms ? validTransforms.includes(name) ? name : shortTransforms.get(name) : false;
8561
+
8562
+ const styleName = individualTransformProperty ? 'transform' : name;
8563
+ if (!inlineStyles[styleName]) {
8564
+ inlineStyles[styleName] = elStyle[styleName];
8565
+ }
8566
+
8350
8567
  let parsedPropertyValue;
8351
8568
  if (isObj(propertyValue)) {
8352
8569
  const tweenOptions = /** @type {WAAPITweenOptions} */(propertyValue);
@@ -8355,7 +8572,7 @@ class WAAPIAnimation {
8355
8572
  const to = /** @type {WAAPITweenOptions} */(tweenOptions).to;
8356
8573
  const from = /** @type {WAAPITweenOptions} */(tweenOptions).from;
8357
8574
  /** @type {Number} */
8358
- tweenParams.duration = (tweenOptionsSpring ? /** @type {Spring} */(tweenOptionsSpring).duration : getFunctionValue(setValue(tweenOptions.duration, duration), $el, i, targetsLength)) * timeScale;
8575
+ tweenParams.duration = (tweenOptionsSpring ? /** @type {Spring} */(tweenOptionsSpring).settlingDuration : getFunctionValue(setValue(tweenOptions.duration, duration), $el, i, targetsLength)) * timeScale;
8359
8576
  /** @type {Number} */
8360
8577
  tweenParams.delay = getFunctionValue(setValue(tweenOptions.delay, delay), $el, i, targetsLength) * timeScale;
8361
8578
  /** @type {CompositeOperation} */
@@ -8372,10 +8589,10 @@ class WAAPIAnimation {
8372
8589
  addWAAPIAnimation(this, $el, name, keyframes, tweenParams);
8373
8590
  if (!isUnd(from)) {
8374
8591
  if (!individualTransformProperty) {
8375
- $el.style[name] = keyframes[name][0];
8592
+ elStyle[name] = keyframes[name][0];
8376
8593
  } else {
8377
8594
  const key = `--${individualTransformProperty}`;
8378
- $el.style.setProperty(key, keyframes[key][0]);
8595
+ elStyle.setProperty(key, keyframes[key][0]);
8379
8596
  }
8380
8597
  }
8381
8598
  } else {
@@ -8396,7 +8613,7 @@ class WAAPIAnimation {
8396
8613
  for (let t in cachedTransforms) {
8397
8614
  transforms += `${transformsFragmentStrings[t]}var(--${t})) `;
8398
8615
  }
8399
- $el.style.transform = transforms;
8616
+ elStyle.transform = transforms;
8400
8617
  }
8401
8618
  });
8402
8619
 
@@ -8441,7 +8658,8 @@ class WAAPIAnimation {
8441
8658
  // Make sure the animation playState is not 'paused' in order to properly trigger an onfinish callback.
8442
8659
  // 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
8660
  // https://developer.mozilla.org/en-US/docs/Web/API/Animation/finish_event
8444
- if (t >= this.duration) anim.play();
8661
+ // This is not needed for persisting animations since they never finish.
8662
+ if (!this.persist && t >= this.duration) anim.play();
8445
8663
  anim.currentTime = t;
8446
8664
  });
8447
8665
  }
@@ -8511,25 +8729,46 @@ class WAAPIAnimation {
8511
8729
  }
8512
8730
 
8513
8731
  cancel() {
8514
- this.forEach('cancel');
8515
- return this.pause();
8732
+ this.muteCallbacks = true; // This prevents triggering the onComplete callback and resolving the Promise
8733
+ return this.commitStyles().forEach('cancel');
8516
8734
  }
8517
8735
 
8518
8736
  revert() {
8519
- this.cancel();
8520
- this.targets.forEach(($el, i) => $el.setAttribute('style', this._inlineStyles[i]) );
8737
+ // NOTE: We need a better way to revert the transforms, since right now the entire transform property value is reverted,
8738
+ // This means if you have multiple animations animating different transforms on the same target,
8739
+ // reverting one of them will also override the transform property of the other animations.
8740
+ // A better approach would be to store the original custom property values is they exist instead of the entire transform value,
8741
+ // and update the CSS variables with the orignal value
8742
+ this.cancel().targets.forEach(($el, i) => {
8743
+ const targetStyle = $el.style;
8744
+ const targetInlineStyles = this._inlineStyles[i];
8745
+ for (let name in targetInlineStyles) {
8746
+ const originalInlinedValue = targetInlineStyles[name];
8747
+ if (isUnd(originalInlinedValue) || originalInlinedValue === emptyString) {
8748
+ targetStyle.removeProperty(toLowerCase(name));
8749
+ } else {
8750
+ targetStyle[name] = originalInlinedValue;
8751
+ }
8752
+ }
8753
+ // Remove style attribute if empty
8754
+ if ($el.getAttribute('style') === emptyString) $el.removeAttribute('style');
8755
+ });
8521
8756
  return this;
8522
8757
  }
8523
8758
 
8524
8759
  /**
8525
- * @param {WAAPICallback} [callback]
8526
- * @return {Promise}
8760
+ * @typedef {this & {then: null}} ResolvedWAAPIAnimation
8761
+ */
8762
+
8763
+ /**
8764
+ * @param {Callback<ResolvedWAAPIAnimation>} [callback]
8765
+ * @return Promise<this>
8527
8766
  */
8528
8767
  then(callback = noop) {
8529
8768
  const then = this.then;
8530
8769
  const onResolve = () => {
8531
8770
  this.then = null;
8532
- callback(this);
8771
+ callback(/** @type {ResolvedWAAPIAnimation} */(this));
8533
8772
  this.then = then;
8534
8773
  this._resolve = noop;
8535
8774
  };
@@ -8551,4 +8790,4 @@ const waapi = {
8551
8790
  convertEase: easingToLinear
8552
8791
  };
8553
8792
 
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 };
8793
+ 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 };