animejs 4.1.1 → 4.1.3

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.
package/lib/anime.esm.js CHANGED
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * anime.js - ESM
3
- * @version v4.1.1
3
+ * @version v4.1.3
4
4
  * @author Julian Garnier
5
5
  * @license MIT
6
6
  * @copyright (c) 2025 Julian Garnier
7
7
  * @see https://animejs.com
8
8
  */
9
9
 
10
- // Global types ///////////////////////////////////////////////////////////////
10
+ // Global types ////////////////////////////////////////////////////////////////
11
11
 
12
12
  /**
13
13
  * @typedef {Object} DefaultsParams
@@ -38,17 +38,18 @@
38
38
  /** @typedef {JSAnimation|Timeline} Renderable */
39
39
  /** @typedef {Timer|Renderable} Tickable */
40
40
  /** @typedef {Timer&JSAnimation&Timeline} CallbackArgument */
41
- /** @typedef {Animatable|Tickable|Draggable|ScrollObserver|TextSplitter|Scope} Revertible */
41
+ /** @typedef {Animatable|Tickable|WAAPIAnimation|Draggable|ScrollObserver|TextSplitter|Scope} Revertible */
42
42
 
43
- // Stagger types //////////////////////////////////////////////////////////////
43
+ // Stagger types ///////////////////////////////////////////////////////////////
44
44
 
45
45
  /**
46
+ * @template T
46
47
  * @callback StaggerFunction
47
48
  * @param {Target} [target]
48
49
  * @param {Number} [index]
49
50
  * @param {Number} [length]
50
51
  * @param {Timeline} [tl]
51
- * @return {Number|String}
52
+ * @return {T}
52
53
  */
53
54
 
54
55
  /**
@@ -58,13 +59,13 @@
58
59
  * @property {Boolean} [reversed]
59
60
  * @property {Array.<Number>} [grid]
60
61
  * @property {('x'|'y')} [axis]
61
- * @property {String|StaggerFunction} [use]
62
+ * @property {String|((target: Target, i: Number, length: Number) => Number)} [use]
62
63
  * @property {Number} [total]
63
64
  * @property {EasingParam} [ease]
64
65
  * @property {TweenModifier} [modifier]
65
66
  */
66
67
 
67
- // Eases types ////////////////////////////////////////////////////////////////
68
+ // Eases types /////////////////////////////////////////////////////////////////
68
69
 
69
70
  /**
70
71
  * @callback EasingFunction
@@ -92,7 +93,17 @@
92
93
  /** @typedef {Array.<TargetSelector>|TargetSelector} TargetsParam */
93
94
  /** @typedef {Array.<Target>} TargetsArray */
94
95
 
95
- // Callback types ////////////////////////////////////////////////////////////
96
+ // Spring types ////////////////////////////////////////////////////////////////
97
+
98
+ /**
99
+ * @typedef {Object} SpringParams
100
+ * @property {Number} [mass=1] - Mass, default 1
101
+ * @property {Number} [stiffness=100] - Stiffness, default 100
102
+ * @property {Number} [damping=10] - Damping, default 10
103
+ * @property {Number} [velocity=0] - Initial velocity, default 0
104
+ */
105
+
106
+ // Callback types //////////////////////////////////////////////////////////////
96
107
 
97
108
  /**
98
109
  * @template T
@@ -119,7 +130,7 @@
119
130
  * @property {Callback<T>} [onRender]
120
131
  */
121
132
 
122
- // Timer types ////////////////////////////////////////////////////////////////
133
+ // Timer types /////////////////////////////////////////////////////////////////
123
134
 
124
135
  /**
125
136
  * @typedef {Object} TimerOptions
@@ -141,7 +152,7 @@
141
152
  * @typedef {TimerOptions & TickableCallbacks<Timer>} TimerParams
142
153
  */
143
154
 
144
- // Tween types ////////////////////////////////////////////////////////////////
155
+ // Tween types /////////////////////////////////////////////////////////////////
145
156
 
146
157
  /**
147
158
  * @callback FunctionValue
@@ -212,7 +223,7 @@
212
223
  /** @typedef {WeakMap.<Target, TweenLookups>} TweenReplaceLookups */
213
224
  /** @typedef {Map.<Target, TweenLookups>} TweenAdditiveLookups */
214
225
 
215
- // Animation types ////////////////////////////////////////////////////////////
226
+ // JSAnimation types ///////////////////////////////////////////////////////////
216
227
 
217
228
  /**
218
229
  * @typedef {Number|String|FunctionValue} TweenParamValue
@@ -286,7 +297,36 @@
286
297
  * @typedef {Record<String, TweenOptions | Callback<JSAnimation> | TweenModifier | boolean | PercentageKeyframes | DurationKeyframes | ScrollObserver> & TimerOptions & AnimationOptions & TweenParamsOptions & TickableCallbacks<JSAnimation> & RenderableCallbacks<JSAnimation>} AnimationParams
287
298
  */
288
299
 
289
- // Timeline types /////////////////////////////////////////////////////////////
300
+ // Timeline types //////////////////////////////////////////////////////////////
301
+
302
+ /**
303
+ * Accepts:<br>
304
+ * - `Number` - Absolute position in milliseconds (e.g., `500` places element at exactly 500ms)<br>
305
+ * - `'+=Number'` - Addition: Position element X ms after the last element (e.g., `'+=100'`)<br>
306
+ * - `'-=Number'` - Subtraction: Position element X ms before the last element's end (e.g., `'-=100'`)<br>
307
+ * - `'*=Number'` - Multiplier: Position element at a fraction of the total duration (e.g., `'*=.5'` for halfway)<br>
308
+ * - `'<'` - Previous end: Position element at the end position of the previous element<br>
309
+ * - `'<<'` - Previous start: Position element at the start position of the previous element<br>
310
+ * - `'<<+=Number'` - Combined: Position element relative to previous element's start (e.g., `'<<+=250'`)<br>
311
+ * - `'label'` - Label: Position element at a named label position (e.g., `'My Label'`)
312
+ *
313
+ * @typedef {Number|`+=${Number}`|`-=${Number}`|`*=${Number}`|'<'|'<<'|`<<+=${Number}`|`<<-=${Number}`|String} TimelinePosition
314
+ */
315
+
316
+ /**
317
+ * Accepts:<br>
318
+ * - `Number` - Absolute position in milliseconds (e.g., `500` places animation at exactly 500ms)<br>
319
+ * - `'+=Number'` - Addition: Position animation X ms after the last animation (e.g., `'+=100'`)<br>
320
+ * - `'-=Number'` - Subtraction: Position animation X ms before the last animation's end (e.g., `'-=100'`)<br>
321
+ * - `'*=Number'` - Multiplier: Position animation at a fraction of the total duration (e.g., `'*=.5'` for halfway)<br>
322
+ * - `'<'` - Previous end: Position animation at the end position of the previous animation<br>
323
+ * - `'<<'` - Previous start: Position animation at the start position of the previous animation<br>
324
+ * - `'<<+=Number'` - Combined: Position animation relative to previous animation's start (e.g., `'<<+=250'`)<br>
325
+ * - `'label'` - Label: Position animation at a named label position (e.g., `'My Label'`)<br>
326
+ * - `stagger(String|Nummber)` - Stagger multi-elements animation positions (e.g., 10, 20, 30...)
327
+ *
328
+ * @typedef {TimelinePosition | StaggerFunction<Number|String>} TimelineAnimationPosition
329
+ */
290
330
 
291
331
  /**
292
332
  * @typedef {Object} TimelineOptions
@@ -298,7 +338,57 @@
298
338
  * @typedef {TimerOptions & TimelineOptions & TickableCallbacks<Timeline> & RenderableCallbacks<Timeline>} TimelineParams
299
339
  */
300
340
 
301
- // Animatable types ///////////////////////////////////////////////////////////
341
+ // WAAPIAnimation types ////////////////////////////////////////////////////////
342
+
343
+ /**
344
+ * @typedef {String|Number|Array<String>|Array<Number>} WAAPITweenValue
345
+ */
346
+
347
+ /**
348
+ * @callback WAAPIFunctionValue
349
+ * @param {DOMTarget} target - The animated target
350
+ * @param {Number} index - The target index
351
+ * @param {Number} length - The total number of animated targets
352
+ * @return {WAAPITweenValue}
353
+ */
354
+
355
+ /**
356
+ * @typedef {WAAPITweenValue|WAAPIFunctionValue|Array<String|Number|WAAPIFunctionValue>} WAAPIKeyframeValue
357
+ */
358
+
359
+ /**
360
+ * @typedef {(animation: WAAPIAnimation) => void} WAAPICallback
361
+ */
362
+
363
+ /**
364
+ * @typedef {Object} WAAPITweenOptions
365
+ * @property {WAAPIKeyframeValue} [to]
366
+ * @property {WAAPIKeyframeValue} [from]
367
+ * @property {Number|WAAPIFunctionValue} [duration]
368
+ * @property {Number|WAAPIFunctionValue} [delay]
369
+ * @property {EasingParam} [ease]
370
+ * @property {CompositeOperation} [composition]
371
+ */
372
+
373
+ /**
374
+ * @typedef {Object} WAAPIAnimationOptions
375
+ * @property {Number|Boolean} [loop]
376
+ * @property {Boolean} [Reversed]
377
+ * @property {Boolean} [Alternate]
378
+ * @property {Boolean|ScrollObserver} [autoplay]
379
+ * @property {Number} [playbackRate]
380
+ * @property {Number|WAAPIFunctionValue} [duration]
381
+ * @property {Number|WAAPIFunctionValue} [delay]
382
+ * @property {EasingParam} [ease]
383
+ * @property {CompositeOperation} [composition]
384
+ * @property {WAAPICallback} [onComplete]
385
+ */
386
+
387
+ /**
388
+ * @typedef {Record<String, WAAPIKeyframeValue | WAAPIAnimationOptions | Boolean | ScrollObserver | WAAPICallback | EasingParam | WAAPITweenOptions> & WAAPIAnimationOptions} WAAPIAnimationParams
389
+ */
390
+
391
+ // Animatable types ////////////////////////////////////////////////////////////
302
392
 
303
393
  /**
304
394
  * @callback AnimatablePropertySetter
@@ -334,7 +424,7 @@
334
424
  * @typedef {Record<String, TweenParamValue | EasingParam | TweenModifier | TweenComposition | AnimatablePropertyParamsOptions> & AnimatablePropertyParamsOptions} AnimatableParams
335
425
  */
336
426
 
337
- // Scope types ////////////////////////////////////////////////////////////////
427
+ // Scope types /////////////////////////////////////////////////////////////////
338
428
 
339
429
  /**
340
430
  * @typedef {Object} ReactRef
@@ -377,7 +467,52 @@
377
467
  * @return {ScopeCleanupCallback|void}
378
468
  */
379
469
 
380
- // Draggable types ////////////////////////////////////////////////////////////
470
+ // Scroll types ////////////////////////////////////////////////////////////////
471
+
472
+ /**
473
+ * @typedef {String|Number} ScrollThresholdValue
474
+ */
475
+
476
+ /**
477
+ * @typedef {Object} ScrollThresholdParam
478
+ * @property {ScrollThresholdValue} [target]
479
+ * @property {ScrollThresholdValue} [container]
480
+ */
481
+
482
+ /**
483
+ * @callback ScrollObserverAxisCallback
484
+ * @param {ScrollObserver} self
485
+ * @return {'x'|'y'}
486
+ */
487
+
488
+ /**
489
+ * @callback ScrollThresholdCallback
490
+ * @param {ScrollObserver} self
491
+ * @return {ScrollThresholdValue|ScrollThresholdParam}
492
+ */
493
+
494
+ /**
495
+ * @typedef {Object} ScrollObserverParams
496
+ * @property {Number|String} [id]
497
+ * @property {Boolean|Number|String|EasingParam} [sync]
498
+ * @property {TargetsParam} [container]
499
+ * @property {TargetsParam} [target]
500
+ * @property {'x'|'y'|ScrollObserverAxisCallback|((observer: ScrollObserver) => 'x'|'y'|ScrollObserverAxisCallback)} [axis]
501
+ * @property {ScrollThresholdValue|ScrollThresholdParam|ScrollThresholdCallback|((observer: ScrollObserver) => ScrollThresholdValue|ScrollThresholdParam|ScrollThresholdCallback)} [enter]
502
+ * @property {ScrollThresholdValue|ScrollThresholdParam|ScrollThresholdCallback|((observer: ScrollObserver) => ScrollThresholdValue|ScrollThresholdParam|ScrollThresholdCallback)} [leave]
503
+ * @property {Boolean|((observer: ScrollObserver) => Boolean)} [repeat]
504
+ * @property {Boolean} [debug]
505
+ * @property {Callback<ScrollObserver>} [onEnter]
506
+ * @property {Callback<ScrollObserver>} [onLeave]
507
+ * @property {Callback<ScrollObserver>} [onEnterForward]
508
+ * @property {Callback<ScrollObserver>} [onLeaveForward]
509
+ * @property {Callback<ScrollObserver>} [onEnterBackward]
510
+ * @property {Callback<ScrollObserver>} [onLeaveBackward]
511
+ * @property {Callback<ScrollObserver>} [onUpdate]
512
+ * @property {Callback<ScrollObserver>} [onSyncComplete]
513
+ */
514
+
515
+ // Draggable types /////////////////////////////////////////////////////////////
381
516
 
382
517
  /**
383
518
  * @typedef {Object} DraggableAxisParam
@@ -426,7 +561,7 @@
426
561
  * @property {Callback<Draggable>} [onAfterResize]
427
562
  */
428
563
 
429
- // Text types /////////////////////////////////////////////////////////////////
564
+ // Text types //////////////////////////////////////////////////////////////////
430
565
 
431
566
  /**
432
567
  * @typedef {Object} splitTemplateParams
@@ -455,7 +590,7 @@
455
590
  * @property {Boolean} [debug]
456
591
  */
457
592
 
458
- // SVG types //////////////////////////////////////////////////////////////////
593
+ // SVG types ///////////////////////////////////////////////////////////////////
459
594
 
460
595
  /**
461
596
  * @typedef {SVGGeometryElement & {
@@ -470,10 +605,10 @@
470
605
  // TODO: Do we need to check if we're running inside a worker ?
471
606
  const isBrowser = typeof window !== 'undefined';
472
607
 
473
- /** @type {Object|Null} */
474
- const win = isBrowser ? window : null;
608
+ /** @type {Window & {AnimeJS: Array}|null} */
609
+ const win = isBrowser ? /** @type {Window & {AnimeJS: Array}} */(/** @type {unknown} */(window)) : null;
475
610
 
476
- /** @type {Document} */
611
+ /** @type {Document|null} */
477
612
  const doc = isBrowser ? document : null;
478
613
 
479
614
  // Enums
@@ -619,13 +754,13 @@ const globals = {
619
754
  defaults,
620
755
  /** @type {Number} */
621
756
  precision: 4,
622
- /** @type {Number} */
757
+ /** @type {Number} equals 1 in ms mode, 0.001 in s mode */
623
758
  timeScale: 1,
624
759
  /** @type {Number} */
625
760
  tickThreshold: 200,
626
761
  };
627
762
 
628
- const globalVersions = { version: '4.1.1', engine: null };
763
+ const globalVersions = { version: '4.1.3', engine: null };
629
764
 
630
765
  if (isBrowser) {
631
766
  if (!win.AnimeJS) win.AnimeJS = [];
@@ -648,7 +783,6 @@ const toLowerCase = str => str.replace(lowerCaseRgx, '$1-$2').toLowerCase();
648
783
  */
649
784
  const stringStartsWith = (str, sub) => str.indexOf(sub) === 0;
650
785
 
651
- // Time
652
786
  // Note: Date.now is used instead of performance.now since it is precise enough for timings calculations, performs slightly faster and works in Node.js environement.
653
787
  const now = Date.now;
654
788
 
@@ -1316,7 +1450,7 @@ const tick = (tickable, time, muteCallbacks, internalRender, tickMode) => {
1316
1450
  if (!muteCallbacks && tlChildrenHasRendered) tl.onRender(/** @type {CallbackArgument} */(tl));
1317
1451
 
1318
1452
  // Triggers the timeline onComplete() once all chindren all completed and the current time has reached the end
1319
- if (tlChildrenHaveCompleted && tl._currentTime >= tl.duration) {
1453
+ if ((tlChildrenHaveCompleted || tlIsRunningBackwards) && tl._currentTime >= tl.duration) {
1320
1454
  // Make sure the paused flag is false in case it has been skipped in the render function
1321
1455
  tl.paused = true;
1322
1456
  if (!tl.completed) {
@@ -1405,9 +1539,10 @@ class Engine extends Clock {
1405
1539
  this.pauseOnDocumentHidden = true;
1406
1540
  /** @type {DefaultsParams} */
1407
1541
  this.defaults = defaults;
1408
- this.paused = isBrowser && doc.hidden ? true : false;
1542
+ // this.paused = isBrowser && doc.hidden ? true : false;
1543
+ this.paused = true;
1409
1544
  /** @type {Number|NodeJS.Immediate} */
1410
- this.reqId = null;
1545
+ this.reqId = 0;
1411
1546
  }
1412
1547
 
1413
1548
  update() {
@@ -1442,13 +1577,16 @@ class Engine extends Clock {
1442
1577
  }
1443
1578
 
1444
1579
  wake() {
1445
- if (this.useDefaultMainLoop && !this.reqId && !this.paused) {
1580
+ if (this.useDefaultMainLoop && !this.reqId) {
1581
+ // Imediatly request a tick to update engine._elapsedTime and get accurate offsetPosition calculation in timer.js
1582
+ this.requestTick(now());
1446
1583
  this.reqId = engineTickMethod(tickEngine);
1447
1584
  }
1448
1585
  return this;
1449
1586
  }
1450
1587
 
1451
1588
  pause() {
1589
+ if (!this.reqId) return;
1452
1590
  this.paused = true;
1453
1591
  return killEngine();
1454
1592
  }
@@ -1589,6 +1727,7 @@ function getNodeList(v) {
1589
1727
  */
1590
1728
  function parseTargets(targets) {
1591
1729
  if (isNil(targets)) return /** @type {TargetsArray} */([]);
1730
+ if (!isBrowser) return /** @type {JSTargetsArray} */(isArr(targets) && targets.flat(Infinity) || [targets]);
1592
1731
  if (isArr(targets)) {
1593
1732
  const flattened = targets.flat(Infinity);
1594
1733
  /** @type {TargetsArray} */
@@ -1629,7 +1768,6 @@ function parseTargets(targets) {
1629
1768
  }
1630
1769
  return parsed;
1631
1770
  }
1632
- if (!isBrowser) return /** @type {JSTargetsArray} */([targets]);
1633
1771
  const nodeList = getNodeList(targets);
1634
1772
  if (nodeList) return /** @type {DOMTargetsArray} */(Array.from(nodeList));
1635
1773
  return /** @type {TargetsArray} */([targets]);
@@ -2279,12 +2417,16 @@ const composeTween = (tween, siblings) => {
2279
2417
 
2280
2418
  const prevChangeStartTime = prevSibling._startTime;
2281
2419
  const prevTLOffset = prevAbsEndTime - (prevChangeStartTime + prevSibling._updateDuration);
2420
+ // Rounding is necessary here to minimize floating point errors when working in seconds
2421
+ const updatedPrevChangeDuration = round(absoluteUpdateStartTime - prevTLOffset - prevChangeStartTime, 12);
2282
2422
 
2283
- prevSibling._changeDuration = absoluteUpdateStartTime - prevTLOffset - prevChangeStartTime;
2284
- prevSibling._currentTime = prevSibling._changeDuration;
2423
+ prevSibling._changeDuration = updatedPrevChangeDuration;
2424
+ prevSibling._currentTime = updatedPrevChangeDuration;
2285
2425
  prevSibling._isOverlapped = 1;
2286
2426
 
2287
- if (prevSibling._changeDuration < minValue) {
2427
+ // Override the previous tween if its new _changeDuration is lower than minValue
2428
+ // TODO: See if it's even neceseeary to test against minValue, checking for 0 might be enough
2429
+ if (updatedPrevChangeDuration < minValue) {
2288
2430
  overrideTween(prevSibling);
2289
2431
  }
2290
2432
  }
@@ -2315,7 +2457,7 @@ const composeTween = (tween, siblings) => {
2315
2457
  prevParent.cancel();
2316
2458
  // Previously, calling .cancel() on a timeline child would affect the render order of other children
2317
2459
  // Worked around this by marking it as .completed and using .pause() for safe removal in the engine loop
2318
- // This is no longer needed since timeline tween composition is now handled separatly
2460
+ // This is no longer needed since timeline tween composition is now handled separately
2319
2461
  // Keeping this here for reference
2320
2462
  // prevParent.completed = true;
2321
2463
  // prevParent.pause();
@@ -2514,18 +2656,17 @@ class Timer extends Clock {
2514
2656
  /** @type {Number} */(timerLoop) < 0 ? Infinity :
2515
2657
  /** @type {Number} */(timerLoop) + 1;
2516
2658
 
2659
+
2517
2660
  let offsetPosition = 0;
2518
2661
 
2519
2662
  if (parent) {
2520
2663
  offsetPosition = parentPosition;
2521
2664
  } else {
2522
- let startTime = now();
2523
- // Make sure to tick the engine once if suspended to avoid big gaps with the following offsetPosition calculation
2524
- if (engine.paused) {
2525
- engine.requestTick(startTime);
2526
- startTime = engine._elapsedTime;
2527
- }
2528
- offsetPosition = startTime - engine._startTime;
2665
+ // Make sure to tick the engine once if not currently running to get up to date engine._elapsedTime
2666
+ // to avoid big gaps with the following offsetPosition calculation
2667
+ if (!engine.reqId) engine.requestTick(now());
2668
+ // Make sure to scale the offset position with globals.timeScale to properly handle seconds unit
2669
+ offsetPosition = (engine._elapsedTime - engine._startTime) * globals.timeScale;
2529
2670
  }
2530
2671
 
2531
2672
  // Timer's parameters
@@ -2726,6 +2867,9 @@ class Timer extends Clock {
2726
2867
  /** @return {this} */
2727
2868
  resetTime() {
2728
2869
  const timeScale = 1 / (this._speed * engine._speed);
2870
+ // TODO: See if we can safely use engine._elapsedTime here
2871
+ // if (!engine.reqId) engine.requestTick(now())
2872
+ // this._startTime = engine._elapsedTime - (this._currentTime + this._delay) * timeScale;
2729
2873
  this._startTime = now() - (this._currentTime + this._delay) * timeScale;
2730
2874
  return this;
2731
2875
  }
@@ -2887,7 +3031,6 @@ class Timer extends Clock {
2887
3031
 
2888
3032
  }
2889
3033
 
2890
-
2891
3034
  /**
2892
3035
  * @param {TimerParams} [parameters]
2893
3036
  * @return {Timer}
@@ -2931,10 +3074,10 @@ const binarySubdivide = (aX, mX1, mX2) => {
2931
3074
  };
2932
3075
 
2933
3076
  /**
2934
- * @param {Number} [mX1]
2935
- * @param {Number} [mY1]
2936
- * @param {Number} [mX2]
2937
- * @param {Number} [mY2]
3077
+ * @param {Number} [mX1] The x coordinate of the first point
3078
+ * @param {Number} [mY1] The y coordinate of the first point
3079
+ * @param {Number} [mX2] The x coordinate of the second point
3080
+ * @param {Number} [mY2] The y coordinate of the second point
2938
3081
  * @return {EasingFunction}
2939
3082
  */
2940
3083
 
@@ -2957,7 +3100,7 @@ const steps = (steps = 10, fromStart) => {
2957
3100
  /**
2958
3101
  * Without parameters, the linear function creates a non-eased transition.
2959
3102
  * Parameters, if used, creates a piecewise linear easing by interpolating linearly between the specified points.
2960
- * @param {...String|Number} [args] - Points
3103
+ * @param {...(String|Number)} args - Points
2961
3104
  * @return {EasingFunction}
2962
3105
  */
2963
3106
  const linear = (...args) => {
@@ -3605,7 +3748,8 @@ class JSAnimation extends Timer {
3605
3748
  const isFromToArray = isArr(tweenToValue);
3606
3749
  const isFromToValue = isFromToArray || (hasFromvalue && hasToValue);
3607
3750
  const tweenStartTime = prevTween ? lastTweenChangeEndTime + tweenDelay : tweenDelay;
3608
- const absoluteStartTime = absoluteOffsetTime + tweenStartTime;
3751
+ // Rounding is necessary here to minimize floating point errors when working in seconds
3752
+ const absoluteStartTime = round(absoluteOffsetTime + tweenStartTime, 12);
3609
3753
 
3610
3754
  // Force a onRender callback if the animation contains at least one from value and autoplay is set to false
3611
3755
  if (!shouldTriggerRender && (hasFromvalue || isFromToArray)) shouldTriggerRender = 1;
@@ -3733,7 +3877,7 @@ class JSAnimation extends Timer {
3733
3877
 
3734
3878
  // Tween factory
3735
3879
 
3736
- // Rounding is necessary here to minimize floating point errors
3880
+ // Rounding is necessary here to minimize floating point errors when working in seconds
3737
3881
  const tweenUpdateDuration = round(+tweenDuration || minValue, 12);
3738
3882
 
3739
3883
  /** @type {Tween} */
@@ -3782,7 +3926,7 @@ class JSAnimation extends Timer {
3782
3926
  if (isNaN(firstTweenChangeStartTime)) {
3783
3927
  firstTweenChangeStartTime = tween._startTime;
3784
3928
  }
3785
- // Rounding is necessary here to minimize floating point errors
3929
+ // Rounding is necessary here to minimize floating point errors when working in seconds
3786
3930
  lastTweenChangeEndTime = round(tweenStartTime + tweenUpdateDuration, 12);
3787
3931
  prevTween = tween;
3788
3932
  animationAnimationLength++;
@@ -3909,7 +4053,8 @@ class JSAnimation extends Timer {
3909
4053
  tween._fromNumber = decomposedOriginalValue.n;
3910
4054
  tween._toNumbers = cloneArray(toTargetObject.d);
3911
4055
  tween._strings = cloneArray(toTargetObject.s);
3912
- tween._toNumber = toTargetObject.n;
4056
+ // Make sure to apply relative operators https://github.com/juliangarnier/anime/issues/1025
4057
+ tween._toNumber = toTargetObject.o ? getRelativeValue(decomposedOriginalValue.n, toTargetObject.n, toTargetObject.o) : toTargetObject.n;
3913
4058
  }
3914
4059
  });
3915
4060
  return this;
@@ -3964,7 +4109,7 @@ const WAAPIEasesLookups = {
3964
4109
 
3965
4110
  const WAAPIeases = /*#__PURE__*/(() => {
3966
4111
  const list = {};
3967
- for (let type in easeTypes) list[type] = a => easeTypes[type](easeInPower(a));
4112
+ for (let type in easeTypes) list[type] = (/** @type {String|Number} */p) => easeTypes[type](easeInPower(p));
3968
4113
  return /** @type {Record<String, EasingFunction>} */(list);
3969
4114
  })();
3970
4115
 
@@ -4000,54 +4145,6 @@ const parseWAAPIEasing = (ease) => {
4000
4145
  return parsedEase;
4001
4146
  };
4002
4147
 
4003
- /**
4004
- * @typedef {String|Number|Array<String>|Array<Number>} WAAPITweenValue
4005
- */
4006
-
4007
- /**
4008
- * @callback WAAPIFunctionvalue
4009
- * @param {DOMTarget} target - The animated target
4010
- * @param {Number} index - The target index
4011
- * @param {Number} length - The total number of animated targets
4012
- * @return {WAAPITweenValue}
4013
- */
4014
-
4015
- /**
4016
- * @typedef {WAAPITweenValue|WAAPIFunctionvalue|Array<String|Number|WAAPIFunctionvalue>} WAAPIKeyframeValue
4017
- */
4018
-
4019
- /**
4020
- * @typedef {(animation: WAAPIAnimation) => void} WAAPICallback
4021
- */
4022
-
4023
- /**
4024
- * @typedef {Object} WAAPITweenOptions
4025
- * @property {WAAPIKeyframeValue} [to]
4026
- * @property {WAAPIKeyframeValue} [from]
4027
- * @property {Number|WAAPIFunctionvalue} [duration]
4028
- * @property {Number|WAAPIFunctionvalue} [delay]
4029
- * @property {EasingParam} [ease]
4030
- * @property {CompositeOperation} [composition]
4031
- */
4032
-
4033
- /**
4034
- * @typedef {Object} WAAPIAnimationOptions
4035
- * @property {Number|Boolean} [loop]
4036
- * @property {Boolean} [Reversed]
4037
- * @property {Boolean} [Alternate]
4038
- * @property {Boolean|ScrollObserver} [autoplay]
4039
- * @property {Number} [playbackRate]
4040
- * @property {Number|WAAPIFunctionvalue} [duration]
4041
- * @property {Number|WAAPIFunctionvalue} [delay]
4042
- * @property {EasingParam} [ease]
4043
- * @property {CompositeOperation} [composition]
4044
- * @property {WAAPICallback} [onComplete]
4045
- */
4046
-
4047
- /**
4048
- * @typedef {Record<String, WAAPIKeyframeValue | WAAPIAnimationOptions | Boolean | ScrollObserver | WAAPICallback | EasingParam | WAAPITweenOptions> & WAAPIAnimationOptions} WAAPIAnimationParams
4049
- */
4050
-
4051
4148
  const transformsShorthands = ['x', 'y', 'z'];
4052
4149
  const commonDefaultPXProperties = [
4053
4150
  'perspective',
@@ -4345,7 +4442,7 @@ class WAAPIAnimation {
4345
4442
  * @return {this}
4346
4443
  */
4347
4444
  forEach(callback) {
4348
- const cb = isStr(callback) ? a => a[callback]() : callback;
4445
+ const cb = isStr(callback) ? (/** @type {globalThis.Animation} */a) => a[callback]() : callback;
4349
4446
  this.animations.forEach(cb);
4350
4447
  return this;
4351
4448
  }
@@ -4878,10 +4975,6 @@ const utils = {
4878
4975
 
4879
4976
 
4880
4977
 
4881
- /**
4882
- * @typedef {Number|String|Function} TimePosition
4883
- */
4884
-
4885
4978
  /**
4886
4979
  * Timeline's children offsets positions parser
4887
4980
  * @param {Timeline} timeline
@@ -4899,7 +4992,7 @@ const getPrevChildOffset = (timeline, timePosition) => {
4899
4992
 
4900
4993
  /**
4901
4994
  * @param {Timeline} timeline
4902
- * @param {TimePosition} [timePosition]
4995
+ * @param {TimelinePosition} [timePosition]
4903
4996
  * @return {Number}
4904
4997
  */
4905
4998
  const parseTimelinePosition = (timeline, timePosition) => {
@@ -5005,17 +5098,17 @@ class Timeline extends Timer {
5005
5098
  * @overload
5006
5099
  * @param {TargetsParam} a1
5007
5100
  * @param {AnimationParams} a2
5008
- * @param {TimePosition} [a3]
5101
+ * @param {TimelinePosition|StaggerFunction<Number|String>} [a3]
5009
5102
  * @return {this}
5010
5103
  *
5011
5104
  * @overload
5012
5105
  * @param {TimerParams} a1
5013
- * @param {TimePosition} [a2]
5106
+ * @param {TimelinePosition} [a2]
5014
5107
  * @return {this}
5015
5108
  *
5016
5109
  * @param {TargetsParam|TimerParams} a1
5017
- * @param {AnimationParams|TimePosition} a2
5018
- * @param {TimePosition} [a3]
5110
+ * @param {TimelinePosition|AnimationParams} a2
5111
+ * @param {TimelinePosition|StaggerFunction<Number|String>} [a3]
5019
5112
  */
5020
5113
  add(a1, a2, a3) {
5021
5114
  const isAnim = isObj(a2);
@@ -5026,7 +5119,7 @@ class Timeline extends Timer {
5026
5119
  const childParams = /** @type {AnimationParams} */(a2);
5027
5120
  // Check for function for children stagger positions
5028
5121
  if (isFnc(a3)) {
5029
- const staggeredPosition = /** @type {Function} */(a3);
5122
+ const staggeredPosition = a3;
5030
5123
  const parsedTargetsArray = parseTargets(/** @type {TargetsParam} */(a1));
5031
5124
  // Store initial duration before adding new children that will change the duration
5032
5125
  const tlDuration = this.duration;
@@ -5035,7 +5128,8 @@ class Timeline extends Timer {
5035
5128
  // Store the original id in order to add specific indexes to the new animations ids
5036
5129
  const id = childParams.id;
5037
5130
  let i = 0;
5038
- const parsedLength = parsedTargetsArray.length;
5131
+ /** @type {Number} */
5132
+ const parsedLength = (parsedTargetsArray.length);
5039
5133
  parsedTargetsArray.forEach((/** @type {Target} */target) => {
5040
5134
  // Create a new parameter object for each staggered children
5041
5135
  const staggeredChildParams = { ...childParams };
@@ -5046,7 +5140,7 @@ class Timeline extends Timer {
5046
5140
  addTlChild(
5047
5141
  staggeredChildParams,
5048
5142
  this,
5049
- staggeredPosition(target, i, parsedLength, this),
5143
+ parseTimelinePosition(this, staggeredPosition(target, i, parsedLength, this)),
5050
5144
  target,
5051
5145
  i,
5052
5146
  parsedLength
@@ -5066,7 +5160,7 @@ class Timeline extends Timer {
5066
5160
  addTlChild(
5067
5161
  /** @type TimerParams */(a1),
5068
5162
  this,
5069
- parseTimelinePosition(this,/** @type TimePosition */(a2)),
5163
+ parseTimelinePosition(this,a2),
5070
5164
  );
5071
5165
  }
5072
5166
  return this.init(1); // 1 = internalRender
@@ -5076,21 +5170,21 @@ class Timeline extends Timer {
5076
5170
  /**
5077
5171
  * @overload
5078
5172
  * @param {Tickable} [synced]
5079
- * @param {TimePosition} [position]
5173
+ * @param {TimelinePosition} [position]
5080
5174
  * @return {this}
5081
5175
  *
5082
5176
  * @overload
5083
5177
  * @param {globalThis.Animation} [synced]
5084
- * @param {TimePosition} [position]
5178
+ * @param {TimelinePosition} [position]
5085
5179
  * @return {this}
5086
5180
  *
5087
5181
  * @overload
5088
5182
  * @param {WAAPIAnimation} [synced]
5089
- * @param {TimePosition} [position]
5183
+ * @param {TimelinePosition} [position]
5090
5184
  * @return {this}
5091
5185
  *
5092
5186
  * @param {Tickable|WAAPIAnimation|globalThis.Animation} [synced]
5093
- * @param {TimePosition} [position]
5187
+ * @param {TimelinePosition} [position]
5094
5188
  */
5095
5189
  sync(synced, position) {
5096
5190
  if (isUnd(synced) || synced && isUnd(synced.pause)) return this;
@@ -5102,7 +5196,7 @@ class Timeline extends Timer {
5102
5196
  /**
5103
5197
  * @param {TargetsParam} targets
5104
5198
  * @param {AnimationParams} parameters
5105
- * @param {TimePosition} [position]
5199
+ * @param {TimelinePosition} [position]
5106
5200
  * @return {this}
5107
5201
  */
5108
5202
  set(targets, parameters, position) {
@@ -5114,7 +5208,7 @@ class Timeline extends Timer {
5114
5208
 
5115
5209
  /**
5116
5210
  * @param {Callback<Timer>} callback
5117
- * @param {TimePosition} [position]
5211
+ * @param {TimelinePosition} [position]
5118
5212
  * @return {this}
5119
5213
  */
5120
5214
  call(callback, position) {
@@ -5124,13 +5218,13 @@ class Timeline extends Timer {
5124
5218
 
5125
5219
  /**
5126
5220
  * @param {String} labelName
5127
- * @param {TimePosition} [position]
5221
+ * @param {TimelinePosition} [position]
5128
5222
  * @return {this}
5129
5223
  *
5130
5224
  */
5131
5225
  label(labelName, position) {
5132
5226
  if (isUnd(labelName) || labelName && !isStr(labelName)) return this;
5133
- this.labels[labelName] = parseTimelinePosition(this,/** @type TimePosition */(position));
5227
+ this.labels[labelName] = parseTimelinePosition(this, position);
5134
5228
  return this;
5135
5229
  }
5136
5230
 
@@ -5202,20 +5296,49 @@ class Animatable {
5202
5296
  */
5203
5297
  constructor(targets, parameters) {
5204
5298
  if (scope.current) scope.current.register(this);
5299
+ const beginHandler = () => {
5300
+ if (this.callbacks.completed) this.callbacks.reset();
5301
+ this.callbacks.play();
5302
+ };
5303
+ const pauseHandler = () => {
5304
+ if (this.callbacks.completed) return;
5305
+ let paused = true;
5306
+ for (let name in this.animations) {
5307
+ const anim = this.animations[name];
5308
+ if (!anim.paused && paused) {
5309
+ paused = false;
5310
+ break;
5311
+ }
5312
+ }
5313
+ if (paused) {
5314
+ this.callbacks.complete();
5315
+ }
5316
+ };
5317
+ /** @type {AnimationParams} */
5318
+ const globalParams = {
5319
+ onBegin: beginHandler,
5320
+ onComplete: pauseHandler,
5321
+ onPause: pauseHandler,
5322
+ };
5205
5323
  /** @type {AnimationParams} */
5206
- const globalParams = {};
5324
+ const callbacksAnimationParams = { v: 1, autoplay: false };
5207
5325
  const properties = {};
5208
5326
  this.targets = [];
5209
5327
  this.animations = {};
5328
+ /** @type {JSAnimation|null} */
5329
+ this.callbacks = null;
5210
5330
  if (isUnd(targets) || isUnd(parameters)) return;
5211
5331
  for (let propName in parameters) {
5212
5332
  const paramValue = parameters[propName];
5213
5333
  if (isKey(propName)) {
5214
5334
  properties[propName] = paramValue;
5335
+ } else if (stringStartsWith(propName, 'on')) {
5336
+ callbacksAnimationParams[propName] = paramValue;
5215
5337
  } else {
5216
5338
  globalParams[propName] = paramValue;
5217
5339
  }
5218
5340
  }
5341
+ this.callbacks = new JSAnimation({ v: 0 }, callbacksAnimationParams);
5219
5342
  for (let propName in properties) {
5220
5343
  const propValue = properties[propName];
5221
5344
  const isObjValue = isObj(propValue);
@@ -5275,6 +5398,7 @@ class Animatable {
5275
5398
  }
5276
5399
  this.animations = {};
5277
5400
  this.targets.length = 0;
5401
+ if (this.callbacks) this.callbacks.revert();
5278
5402
  return this;
5279
5403
  }
5280
5404
  }
@@ -5284,7 +5408,7 @@ class Animatable {
5284
5408
  * @param {AnimatableParams} parameters
5285
5409
  * @return {AnimatableObject}
5286
5410
  */
5287
- const createAnimatable = (targets, parameters) => /** @type {AnimatableObject} */(new Animatable(targets, parameters));
5411
+ const createAnimatable = (targets, parameters) => /** @type {AnimatableObject} */ (new Animatable(targets, parameters));
5288
5412
 
5289
5413
 
5290
5414
 
@@ -5294,6 +5418,8 @@ const createAnimatable = (targets, parameters) => /** @type {AnimatableObject} *
5294
5418
  * Webkit Copyright © 2016 Apple Inc
5295
5419
  */
5296
5420
 
5421
+ const maxSpringParamValue = K * 10;
5422
+
5297
5423
  /**
5298
5424
  * @typedef {Object} SpringParams
5299
5425
  * @property {Number} [mass=1] - Mass, default 1
@@ -5301,7 +5427,6 @@ const createAnimatable = (targets, parameters) => /** @type {AnimatableObject} *
5301
5427
  * @property {Number} [damping=10] - Damping, default 10
5302
5428
  * @property {Number} [velocity=0] - Initial velocity, default 0
5303
5429
  */
5304
-
5305
5430
  class Spring {
5306
5431
  /**
5307
5432
  * @param {SpringParams} [parameters]
@@ -5313,10 +5438,10 @@ class Spring {
5313
5438
  this.maxDuration = 60000; // The maximum allowed spring duration in ms (default 1 min)
5314
5439
  this.maxRestSteps = this.restDuration / this.timeStep / K; // How many steps allowed after reaching restThreshold before stopping the duration calculation
5315
5440
  this.maxIterations = this.maxDuration / this.timeStep / K; // Calculate the maximum iterations allowed based on maxDuration
5316
- this.m = clamp(setValue(parameters.mass, 1), 0, K);
5317
- this.s = clamp(setValue(parameters.stiffness, 100), 1, K);
5318
- this.d = clamp(setValue(parameters.damping, 10), .1, K);
5319
- this.v = clamp(setValue(parameters.velocity, 0), -1e3, K);
5441
+ this.m = clamp(setValue(parameters.mass, 1), 0, maxSpringParamValue);
5442
+ this.s = clamp(setValue(parameters.stiffness, 100), 1, maxSpringParamValue);
5443
+ this.d = clamp(setValue(parameters.damping, 10), .1, maxSpringParamValue);
5444
+ this.v = clamp(setValue(parameters.velocity, 0), -1e4, maxSpringParamValue);
5320
5445
  this.w0 = 0;
5321
5446
  this.zeta = 0;
5322
5447
  this.wd = 0;
@@ -5367,7 +5492,7 @@ class Spring {
5367
5492
  }
5368
5493
 
5369
5494
  set mass(v) {
5370
- this.m = clamp(setValue(v, 1), 0, K);
5495
+ this.m = clamp(setValue(v, 1), 0, maxSpringParamValue);
5371
5496
  this.compute();
5372
5497
  }
5373
5498
 
@@ -5376,7 +5501,7 @@ class Spring {
5376
5501
  }
5377
5502
 
5378
5503
  set stiffness(v) {
5379
- this.s = clamp(setValue(v, 100), 1, K);
5504
+ this.s = clamp(setValue(v, 100), 1, maxSpringParamValue);
5380
5505
  this.compute();
5381
5506
  }
5382
5507
 
@@ -5385,7 +5510,7 @@ class Spring {
5385
5510
  }
5386
5511
 
5387
5512
  set damping(v) {
5388
- this.d = clamp(setValue(v, 10), .1, K);
5513
+ this.d = clamp(setValue(v, 10), .1, maxSpringParamValue);
5389
5514
  this.compute();
5390
5515
  }
5391
5516
 
@@ -5394,7 +5519,7 @@ class Spring {
5394
5519
  }
5395
5520
 
5396
5521
  set velocity(v) {
5397
- this.v = clamp(setValue(v, 0), -1e3, K);
5522
+ this.v = clamp(setValue(v, 0), -1e4, maxSpringParamValue);
5398
5523
  this.compute();
5399
5524
  }
5400
5525
  }
@@ -5693,32 +5818,23 @@ class Draggable {
5693
5818
  this.touchActionStyles = null;
5694
5819
  this.transforms = new Transforms(this.$target);
5695
5820
  this.overshootCoords = { x: 0, y: 0 };
5696
- this.overshootXTicker = new Timer({ autoplay: false }, null, 0).init();
5697
- this.overshootYTicker = new Timer({ autoplay: false }, null, 0).init();
5698
- this.updateTicker = new Timer({ autoplay: false }, null, 0).init();
5699
- this.overshootXTicker.onUpdate = () => {
5700
- if (this.disabled[0]) return;
5701
- this.updated = true;
5702
- this.manual = true;
5703
- this.animate[this.xProp](this.overshootCoords.x, 0);
5704
- };
5705
- this.overshootXTicker.onComplete = () => {
5706
- if (this.disabled[0]) return;
5707
- this.manual = false;
5708
- this.animate[this.xProp](this.overshootCoords.x, 0);
5709
- };
5710
- this.overshootYTicker.onUpdate = () => {
5711
- if (this.disabled[1]) return;
5712
- this.updated = true;
5713
- this.manual = true;
5714
- this.animate[this.yProp](this.overshootCoords.y, 0);
5715
- };
5716
- this.overshootYTicker.onComplete = () => {
5717
- if (this.disabled[1]) return;
5718
- this.manual = false;
5719
- this.animate[this.yProp](this.overshootCoords.y, 0);
5720
- };
5721
- this.updateTicker.onUpdate = () => this.update();
5821
+ this.overshootTicker = new Timer({
5822
+ autoplay: false,
5823
+ onUpdate: () => {
5824
+ this.updated = true;
5825
+ this.manual = true;
5826
+ // Use a duration of 1 to prevent the animatable from completing immediately to prevent issues with onSettle()
5827
+ // https://github.com/juliangarnier/anime/issues/1045
5828
+ if (!this.disabled[0]) this.animate[this.xProp](this.overshootCoords.x, 1);
5829
+ if (!this.disabled[1]) this.animate[this.yProp](this.overshootCoords.y, 1);
5830
+ },
5831
+ onComplete: () => {
5832
+ this.manual = false;
5833
+ if (!this.disabled[0]) this.animate[this.xProp](this.overshootCoords.x, 0);
5834
+ if (!this.disabled[1]) this.animate[this.yProp](this.overshootCoords.y, 0);
5835
+ },
5836
+ }, null, 0).init();
5837
+ this.updateTicker = new Timer({ autoplay: false, onUpdate: () => this.update() }, null,0,).init();
5722
5838
  this.contained = !isUnd(container);
5723
5839
  this.manual = false;
5724
5840
  this.grabbed = false;
@@ -5729,7 +5845,7 @@ class Draggable {
5729
5845
  this.enabled = false;
5730
5846
  this.initialized = false;
5731
5847
  this.activeProp = this.disabled[1] ? xProp : yProp;
5732
- this.animate.animations[this.activeProp].onRender = () => {
5848
+ this.animate.callbacks.onRender = () => {
5733
5849
  const hasUpdated = this.updated;
5734
5850
  const hasMoved = this.grabbed && hasUpdated;
5735
5851
  const hasReleased = !hasMoved && this.released;
@@ -5741,7 +5857,9 @@ class Draggable {
5741
5857
  this.deltaY = dy;
5742
5858
  this.coords[2] = x;
5743
5859
  this.coords[3] = y;
5744
- if (hasUpdated) {
5860
+ // Check if dx or dy are not 0 to check if the draggable has actually moved
5861
+ // https://github.com/juliangarnier/anime/issues/1032
5862
+ if (hasUpdated && (dx || dy)) {
5745
5863
  this.onUpdate(this);
5746
5864
  }
5747
5865
  if (!hasReleased) {
@@ -5751,9 +5869,9 @@ class Draggable {
5751
5869
  this.angle = atan2(dy, dx);
5752
5870
  }
5753
5871
  };
5754
- this.animate.animations[this.activeProp].onComplete = () => {
5872
+ this.animate.callbacks.onComplete = () => {
5755
5873
  if ((!this.grabbed && this.released)) {
5756
- // Set eleased to false before calling onSettle to avoid recursion
5874
+ // Set released to false before calling onSettle to avoid recursion
5757
5875
  this.released = false;
5758
5876
  }
5759
5877
  if (!this.manual) {
@@ -5821,7 +5939,7 @@ class Draggable {
5821
5939
  setX(x, muteUpdateCallback = false) {
5822
5940
  if (this.disabled[0]) return;
5823
5941
  const v = round(x, 5);
5824
- this.overshootXTicker.pause();
5942
+ this.overshootTicker.pause();
5825
5943
  this.manual = true;
5826
5944
  this.updated = !muteUpdateCallback;
5827
5945
  this.destX = v;
@@ -5839,7 +5957,7 @@ class Draggable {
5839
5957
  setY(y, muteUpdateCallback = false) {
5840
5958
  if (this.disabled[1]) return;
5841
5959
  const v = round(y, 5);
5842
- this.overshootYTicker.pause();
5960
+ this.overshootTicker.pause();
5843
5961
  this.manual = true;
5844
5962
  this.updated = !muteUpdateCallback;
5845
5963
  this.destY = v;
@@ -5896,6 +6014,9 @@ class Draggable {
5896
6014
 
5897
6015
  updateBoundingValues() {
5898
6016
  const $container = this.$container;
6017
+ // Return early if no $container defined to prevents error when reading scrollWidth / scrollHeight
6018
+ // https://github.com/juliangarnier/anime/issues/1064
6019
+ if (!$container) return;
5899
6020
  const cx = this.x;
5900
6021
  const cy = this.y;
5901
6022
  const cx2 = this.coords[2];
@@ -5965,14 +6086,13 @@ class Draggable {
5965
6086
  }
5966
6087
 
5967
6088
  /**
5968
- * Returns 0 if not OB, 1 if x is OB, 2 if y is OB, 3 if both x and y are OB
5969
- *
5970
6089
  * @param {Array} bounds
5971
6090
  * @param {Number} x
5972
6091
  * @param {Number} y
5973
6092
  * @return {Number}
5974
6093
  */
5975
6094
  isOutOfBounds(bounds, x, y) {
6095
+ // Returns 0 if not OB, 1 if x is OB, 2 if y is OB, 3 if both x and y are OB
5976
6096
  if (!this.contained) return 0;
5977
6097
  const [ bt, br, bb, bl ] = bounds;
5978
6098
  const [ dx, dy ] = this.disabled;
@@ -6105,8 +6225,7 @@ class Draggable {
6105
6225
 
6106
6226
  stop() {
6107
6227
  this.updateTicker.pause();
6108
- this.overshootXTicker.pause();
6109
- this.overshootYTicker.pause();
6228
+ this.overshootTicker.pause();
6110
6229
  // Pauses the in bounds onRelease animations
6111
6230
  for (let prop in this.animate.animations) this.animate.animations[prop].pause();
6112
6231
  remove(this, null, 'x');
@@ -6194,7 +6313,7 @@ class Draggable {
6194
6313
  */
6195
6314
  handleDown(e) {
6196
6315
  const $eTarget = /** @type {HTMLElement} */(e.target);
6197
- if (this.grabbed || /** @type {HTMLInputElement} */($eTarget).type === 'range') return;
6316
+ if (this.grabbed || /** @type {HTMLInputElement} */($eTarget).type === 'range') return;
6198
6317
 
6199
6318
  e.stopPropagation();
6200
6319
 
@@ -6413,8 +6532,7 @@ class Draggable {
6413
6532
  composition,
6414
6533
  }).init();
6415
6534
 
6416
- this.overshootXTicker.stretch(durationX).restart();
6417
- this.overshootYTicker.stretch(durationY).restart();
6535
+ this.overshootTicker.stretch(max(durationX, durationY)).restart();
6418
6536
 
6419
6537
  } else {
6420
6538
 
@@ -6526,7 +6644,6 @@ class Draggable {
6526
6644
  this.targetStyles.revert();
6527
6645
  this.targetStyles = null;
6528
6646
  }
6529
- this.stop();
6530
6647
  this.$target.classList.add('is-disabled');
6531
6648
  this.$trigger.removeEventListener('touchstart', this);
6532
6649
  this.$trigger.removeEventListener('mousedown', this);
@@ -6545,10 +6662,10 @@ class Draggable {
6545
6662
  this.disable();
6546
6663
  this.$target.classList.remove('is-disabled');
6547
6664
  this.updateTicker.revert();
6548
- this.overshootXTicker.revert();
6549
- this.overshootYTicker.revert();
6665
+ this.overshootTicker.revert();
6550
6666
  this.resizeTicker.revert();
6551
6667
  this.animate.revert();
6668
+ this.resizeObserver.disconnect();
6552
6669
  return this;
6553
6670
  }
6554
6671
 
@@ -6818,15 +6935,11 @@ class Scope {
6818
6935
  */
6819
6936
  const createScope = params => new Scope(params);
6820
6937
 
6821
- /**
6822
- * @typedef {String|Number} ScrollThresholdValue
6823
- */
6824
-
6825
6938
  /**
6826
6939
  * @return {Number}
6827
6940
  */
6828
6941
  const getMaxViewHeight = () => {
6829
- const $el = document.createElement('div');
6942
+ const $el = doc.createElement('div');
6830
6943
  doc.body.appendChild($el);
6831
6944
  $el.style.height = '100lvh';
6832
6945
  const height = $el.offsetHeight;
@@ -6973,8 +7086,8 @@ class ScrollContainer {
6973
7086
  height = this.winHeight;
6974
7087
  } else {
6975
7088
  const elRect = $el.getBoundingClientRect();
6976
- width = elRect.width;
6977
- height = elRect.height;
7089
+ width = $el.clientWidth;
7090
+ height = $el.clientHeight;
6978
7091
  this.top = elRect.top;
6979
7092
  this.left = elRect.left;
6980
7093
  }
@@ -7025,7 +7138,7 @@ class ScrollContainer {
7025
7138
  this.dataTimer.cancel();
7026
7139
  this.resizeTicker.cancel();
7027
7140
  this.wakeTicker.cancel();
7028
- this.resizeObserver.unobserve(this.element);
7141
+ this.resizeObserver.disconnect();
7029
7142
  (this.useWin ? win : this.element).removeEventListener('scroll', this);
7030
7143
  scrollContainers.delete(this.element);
7031
7144
  }
@@ -7132,45 +7245,6 @@ let scrollerIndex = 0;
7132
7245
 
7133
7246
  const debugColors$1 = ['#FF4B4B','#FF971B','#FFC730','#F9F640','#7AFF5A','#18FF74','#17E09B','#3CFFEC','#05DBE9','#33B3F1','#638CF9','#C563FE','#FF4FCF','#F93F8A'];
7134
7247
 
7135
- /**
7136
- * @typedef {Object} ScrollThresholdParam
7137
- * @property {ScrollThresholdValue} [target]
7138
- * @property {ScrollThresholdValue} [container]
7139
- */
7140
-
7141
- /**
7142
- * @callback ScrollObserverAxisCallback
7143
- * @param {ScrollObserver} self
7144
- * @return {'x'|'y'}
7145
- */
7146
-
7147
- /**
7148
- * @callback ScrollThresholdCallback
7149
- * @param {ScrollObserver} self
7150
- * @return {ScrollThresholdValue|ScrollThresholdParam}
7151
- */
7152
-
7153
- /**
7154
- * @typedef {Object} ScrollObserverParams
7155
- * @property {Number|String} [id]
7156
- * @property {Boolean|Number|String|EasingParam} [sync]
7157
- * @property {TargetsParam} [container]
7158
- * @property {TargetsParam} [target]
7159
- * @property {'x'|'y'|ScrollObserverAxisCallback|((observer: ScrollObserver) => 'x'|'y'|ScrollObserverAxisCallback)} [axis]
7160
- * @property {ScrollThresholdValue|ScrollThresholdParam|ScrollThresholdCallback|((observer: ScrollObserver) => ScrollThresholdValue|ScrollThresholdParam|ScrollThresholdCallback)} [enter]
7161
- * @property {ScrollThresholdValue|ScrollThresholdParam|ScrollThresholdCallback|((observer: ScrollObserver) => ScrollThresholdValue|ScrollThresholdParam|ScrollThresholdCallback)} [leave]
7162
- * @property {Boolean|((observer: ScrollObserver) => Boolean)} [repeat]
7163
- * @property {Boolean} [debug]
7164
- * @property {Callback<ScrollObserver>} [onEnter]
7165
- * @property {Callback<ScrollObserver>} [onLeave]
7166
- * @property {Callback<ScrollObserver>} [onEnterForward]
7167
- * @property {Callback<ScrollObserver>} [onLeaveForward]
7168
- * @property {Callback<ScrollObserver>} [onEnterBackward]
7169
- * @property {Callback<ScrollObserver>} [onLeaveBackward]
7170
- * @property {Callback<ScrollObserver>} [onUpdate]
7171
- * @property {Callback<ScrollObserver>} [onSyncComplete]
7172
- */
7173
-
7174
7248
  class ScrollObserver {
7175
7249
  /**
7176
7250
  * @param {ScrollObserverParams} parameters
@@ -7254,8 +7328,8 @@ class ScrollObserver {
7254
7328
  this.forceEnter = false;
7255
7329
  /** @type {Boolean} */
7256
7330
  this.hasEntered = false;
7257
- /** @type {Array.<Number>} */
7258
- this.offsets = [];
7331
+ // /** @type {Array.<Number>} */
7332
+ // this.offsets = [];
7259
7333
  /** @type {Number} */
7260
7334
  this.offset = 0;
7261
7335
  /** @type {Number} */
@@ -7499,33 +7573,46 @@ class ScrollObserver {
7499
7573
  const linked = this.linked;
7500
7574
  let linkedTime;
7501
7575
  let $el = $target;
7502
- let offsetX = 0;
7503
- let offsetY = 0;
7576
+ // let offsetX = 0;
7577
+ // let offsetY = 0;
7578
+ // let $offsetParent = $el;
7504
7579
  /** @type {Element} */
7505
- let $offsetParent = $el;
7506
7580
  if (linked) {
7507
7581
  linkedTime = linked.currentTime;
7508
7582
  linked.seek(0, true);
7509
7583
  }
7510
- const isContainerStatic = getTargetValue(container.element, 'position') === 'static' ? setTargetValues(container.element, { position: 'relative '}) : false;
7584
+ /* Old implementation to get offset and targetSize before fixing https://github.com/juliangarnier/anime/issues/1021
7585
+ // const isContainerStatic = getTargetValue(container.element, 'position') === 'static' ? setTargetValues(container.element, { position: 'relative '}) : false;
7586
+ // while ($el && $el !== container.element && $el !== doc.body) {
7587
+ // const isSticky = getTargetValue($el, 'position') === 'sticky' ?
7588
+ // setTargetValues($el, { position: 'static' }) :
7589
+ // false;
7590
+ // if ($el === $offsetParent) {
7591
+ // offsetX += $el.offsetLeft || 0;
7592
+ // offsetY += $el.offsetTop || 0;
7593
+ // $offsetParent = $el.offsetParent;
7594
+ // }
7595
+ // $el = /** @type {HTMLElement} */($el.parentElement);
7596
+ // if (isSticky) {
7597
+ // if (!stickys) stickys = [];
7598
+ // stickys.push(isSticky);
7599
+ // }
7600
+ // }
7601
+ // if (isContainerStatic) isContainerStatic.revert();
7602
+ // const offset = isHori ? offsetX : offsetY;
7603
+ // const targetSize = isHori ? $target.offsetWidth : $target.offsetHeight;
7604
+
7511
7605
  while ($el && $el !== container.element && $el !== doc.body) {
7512
- const isSticky = getTargetValue($el, 'position') === 'sticky' ?
7513
- setTargetValues($el, { position: 'static' }) :
7514
- false;
7515
- if ($el === $offsetParent) {
7516
- offsetX += $el.offsetLeft || 0;
7517
- offsetY += $el.offsetTop || 0;
7518
- $offsetParent = $el.offsetParent;
7519
- }
7520
- $el = /** @type {HTMLElement} */($el.parentElement);
7606
+ const isSticky = getTargetValue($el, 'position') === 'sticky' ? setTargetValues($el, { position: 'static' }) : false;
7607
+ $el = $el.parentElement;
7521
7608
  if (isSticky) {
7522
7609
  if (!stickys) stickys = [];
7523
7610
  stickys.push(isSticky);
7524
7611
  }
7525
7612
  }
7526
- if (isContainerStatic) isContainerStatic.revert();
7527
- const offset = isHori ? offsetX : offsetY;
7528
- const targetSize = isHori ? $target.offsetWidth : $target.offsetHeight;
7613
+ const rect = $target.getBoundingClientRect();
7614
+ const offset = isHori ? rect.left + container.scrollX - container.left : rect.top + container.scrollY - container.top;
7615
+ const targetSize = isHori ? rect.width : rect.height;
7529
7616
  const containerSize = isHori ? container.width : container.height;
7530
7617
  const scrollSize = isHori ? container.scrollWidth : container.scrollHeight;
7531
7618
  const maxScroll = scrollSize - containerSize;
@@ -7574,8 +7661,8 @@ class ScrollObserver {
7574
7661
  const offsetStart = parsedEnterTarget + offset - parsedEnterContainer;
7575
7662
  const offsetEnd = parsedLeaveTarget + offset - parsedLeaveContainer;
7576
7663
  const scrollDelta = offsetEnd - offsetStart;
7577
- this.offsets[0] = offsetX;
7578
- this.offsets[1] = offsetY;
7664
+ // this.offsets[0] = offsetX;
7665
+ // this.offsets[1] = offsetY;
7579
7666
  this.offset = offset;
7580
7667
  this.offsetStart = offsetStart;
7581
7668
  this.offsetEnd = offsetEnd;
@@ -7731,7 +7818,7 @@ const onScroll = (parameters = {}) => new ScrollObserver(parameters);
7731
7818
 
7732
7819
 
7733
7820
 
7734
- const segmenter = !isUnd(Intl) && Intl.Segmenter;
7821
+ const segmenter = (typeof Intl !== 'undefined') && Intl.Segmenter;
7735
7822
  const valueRgx = /\{value\}/g;
7736
7823
  const indexRgx = /\{i\}/g;
7737
7824
  const whiteSpaceGroupRgx = /(\s+)/;
@@ -8186,9 +8273,33 @@ const text = {
8186
8273
 
8187
8274
 
8188
8275
  /**
8189
- * @param {Number|String|[Number|String,Number|String]} val
8190
- * @param {StaggerParams} params
8191
- * @return {StaggerFunction}
8276
+ * @overload
8277
+ * @param {Number} val
8278
+ * @param {StaggerParams} [params]
8279
+ * @return {StaggerFunction<Number>}
8280
+ */
8281
+ /**
8282
+ * @overload
8283
+ * @param {String} val
8284
+ * @param {StaggerParams} [params]
8285
+ * @return {StaggerFunction<String>}
8286
+ */
8287
+ /**
8288
+ * @overload
8289
+ * @param {[Number, Number]} val
8290
+ * @param {StaggerParams} [params]
8291
+ * @return {StaggerFunction<Number>}
8292
+ */
8293
+ /**
8294
+ * @overload
8295
+ * @param {[String, String]} val
8296
+ * @param {StaggerParams} [params]
8297
+ * @return {StaggerFunction<String>}
8298
+ */
8299
+ /**
8300
+ * @param {Number|String|[Number, Number]|[String, String]} val The staggered value or range
8301
+ * @param {StaggerParams} [params] The stagger parameters
8302
+ * @return {StaggerFunction<Number|String>}
8192
8303
  */
8193
8304
  const stagger = (val, params = {}) => {
8194
8305
  let values = [];