PageSourceSearch

https://visitezliege.be/_content/NetCo_Access_CoreRCL/js/source/Anime/anime.umd.js

js visitezliege.be collected 2026-10-02 10:25:42 UTC 382,977 bytes, 10,450 lines download raw bytes

1/**
2 * Anime.js - UMD bundle
3 * @version v4.3.2
4 * @license MIT
5 * @copyright 2026 - Julian Garnier
6 */
7
8// Global types
9
10/**
11 * @typedef {Object} DefaultsParams
12 * @property {Number|String} [id]
13 * @property {PercentageKeyframes|DurationKeyframes} [keyframes]
14 * @property {EasingParam} [playbackEase]
15 * @property {Number} [playbackRate]
16 * @property {Number} [frameRate]
17 * @property {Number|Boolean} [loop]
18 * @property {Boolean} [reversed]
19 * @property {Boolean} [alternate]
20 * @property {Boolean} [persist]
21 * @property {Boolean|ScrollObserver} [autoplay]
22 * @property {Number|FunctionValue} [duration]
23 * @property {Number|FunctionValue} [delay]
24 * @property {Number} [loopDelay]
25 * @property {EasingParam|FunctionValue} [ease]
26 * @property {'none'|'replace'|'blend'|compositionTypes} [composition]
27 * @property {(v: any) => any} [modifier]
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]
35 */
36
37/** @typedef {JSAnimation|Timeline} Renderable */
38/** @typedef {Timer|Renderable} Tickable */
39/** @typedef {Timer&JSAnimation&Timeline} CallbackArgument */
40/** @typedef {Animatable|Tickable|WAAPIAnimation|Draggable|ScrollObserver|TextSplitter|Scope|AutoLayout} Revertible */
41
42// Stagger types
43
44/**
45 * @template T
46 * @callback StaggerFunction
47 * @param {Target} [target]
48 * @param {Number} [index]
49 * @param {Number} [length]
50 * @param {Timeline} [tl]
51 * @return {T}
52 */
53
54/**
55 * @typedef  {Object} StaggerParams
56 * @property {Number|String} [start]
57 * @property {Number|'first'|'center'|'last'|'random'} [from]
58 * @property {Boolean} [reversed]
59 * @property {Array.<Number>} [grid]
60 * @property {('x'|'y')} [axis]
61 * @property {String|((target: Target, i: Number, length: Number) => Number)} [use]
62 * @property {Number} [total]
63 * @property {EasingParam} [ease]
64 * @property {TweenModifier} [modifier]
65 */
66
67// Targets types
68
69/** @typedef {HTMLElement|SVGElement} DOMTarget */
70/** @typedef {Record<String, any>} JSTarget */
71/** @typedef {DOMTarget|JSTarget} Target */
72/** @typedef {Target|NodeList|String} TargetSelector */
73/** @typedef {DOMTarget|NodeList|String} DOMTargetSelector */
74/** @typedef {Array.<DOMTargetSelector>|DOMTargetSelector} DOMTargetsParam */
75/** @typedef {Array.<DOMTarget>} DOMTargetsArray */
76/** @typedef {Array.<JSTarget>|JSTarget} JSTargetsParam */
77/** @typedef {Array.<JSTarget>} JSTargetsArray */
78/** @typedef {Array.<TargetSelector>|TargetSelector} TargetsParam */
79/** @typedef {Array.<Target>} TargetsArray */
80
81// Eases types
82
83/**
84 * @callback EasingFunction
85 * @param {Number} time
86 * @return {Number}
87 */
88
89/**
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
95 */
96
97/**
98 * @callback PowerEasing
99 * @param {Number|String} [power=1.675]
100 * @return {EasingFunction}
101 */
102
103/**
104 * @callback BackEasing
105 * @param {Number|String} [overshoot=1.7]
106 * @return {EasingFunction}
107 */
108
109/**
110 * @callback ElasticEasing
111 * @param {Number|String} [amplitude=1]
112 * @param {Number|String} [period=.3]
113 * @return {EasingFunction}
114 */
115
116/** @typedef {PowerEasing|BackEasing|ElasticEasing} EasingFunctionWithParams */
117
118// A hack to get both ease names suggestions AND allow any strings
119// https://github.com/microsoft/TypeScript/issues/29729#issuecomment-460346421
120/** @typedef {(String & {})|EaseStringParamNames|EasingFunction|Spring} EasingParam */
121/** @typedef {(String & {})|EaseStringParamNames|WAAPIEaseStringParamNames|EasingFunction|Spring} WAAPIEasingParam */
122
123// Spring types
124
125/**
126 * @typedef {Object} SpringParams
127 * @property {Number} [mass=1] - Mass, default 1
128 * @property {Number} [stiffness=100] - Stiffness, default 100
129 * @property {Number} [damping=10] - Damping, default 10
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
134 */
135
136 // Callback types
137
138/**
139 * @template T
140 * @callback Callback
141 * @param {T} self - Returns itself
142 * @param {PointerEvent} [e]
143 * @return {*}
144 */
145
146/**
147 * @template {object} T
148 * @typedef {Object} TickableCallbacks
149 * @property {Callback<T>} [onBegin]
150 * @property {Callback<T>} [onBeforeUpdate]
151 * @property {Callback<T>} [onUpdate]
152 * @property {Callback<T>} [onLoop]
153 * @property {Callback<T>} [onPause]
154 * @property {Callback<T>} [onComplete]
155 */
156
157/**
158 * @template {object} T
159 * @typedef {Object} RenderableCallbacks
160 * @property {Callback<T>} [onRender]
161 */
162
163// Timer types
164
165/**
166 * @typedef {Object} TimerOptions
167 * @property {Number|String} [id]
168 * @property {TweenParamValue} [duration]
169 * @property {TweenParamValue} [delay]
170 * @property {Number} [loopDelay]
171 * @property {Boolean} [reversed]
172 * @property {Boolean} [alternate]
173 * @property {Boolean|Number} [loop]
174 * @property {Boolean|ScrollObserver} [autoplay]
175 * @property {Number} [frameRate]
176 * @property {Number} [playbackRate]
177 */
178
179/**
180 * @typedef {TimerOptions & TickableCallbacks<Timer>} TimerParams
181 */
182
183// Tween types
184
185/**
186 * @callback FunctionValue
187 * @param {Target} target - The animated target
188 * @param {Number} index - The target index
189 * @param {Number} length - The total number of animated targets
190 * @return {Number|String|TweenObjectValue|EasingParam|Array.<Number|String|TweenObjectValue>}
191 */
192
193/**
194 * @callback TweenModifier
195 * @param {Number} value - The animated value
196 * @return {Number|String}
197 */
198
199/** @typedef {[Number, Number, Number, Number]} ColorArray */
200
201/**
202 * @typedef {Object} Tween
203 * @property {Number} id
204 * @property {JSAnimation} parent
205 * @property {String} property
206 * @property {Target} target
207 * @property {String|Number} _value
208 * @property {Function|null} _func
209 * @property {EasingFunction} _ease
210 * @property {Array.<Number>} _fromNumbers
211 * @property {Array.<Number>} _toNumbers
212 * @property {Array.<String>} _strings
213 * @property {Number} _fromNumber
214 * @property {Number} _toNumber
215 * @property {Array.<Number>} _numbers
216 * @property {Number} _number
217 * @property {String} _unit
218 * @property {TweenModifier} _modifier
219 * @property {Number} _currentTime
220 * @property {Number} _delay
221 * @property {Number} _updateDuration
222 * @property {Number} _startTime
223 * @property {Number} _changeDuration
224 * @property {Number} _absoluteStartTime
225 * @property {tweenTypes} _tweenType
226 * @property {valueTypes} _valueType
227 * @property {Number} _composition
228 * @property {Number} _isOverlapped
229 * @property {Number} _isOverridden
230 * @property {Number} _renderTransforms
231 * @property {String} _inlineValue
232 * @property {Tween} _prevRep
233 * @property {Tween} _nextRep
234 * @property {Tween} _prevAdd
235 * @property {Tween} _nextAdd
236 * @property {Tween} _prev
237 * @property {Tween} _next
238 */
239
240/**
241 * @typedef TweenDecomposedValue
242 * @property {Number} t - Type
243 * @property {Number} n - Single number value
244 * @property {String} u - Value unit
245 * @property {String} o - Value operator
246 * @property {Array.<Number>} d - Array of Numbers (in case of complex value type)
247 * @property {Array.<String>} s - Strings (in case of complex value type)
248 */
249
250/** @typedef {{_head: null|Tween, _tail: null|Tween}} TweenPropertySiblings */
251/** @typedef {Record<String, TweenPropertySiblings>} TweenLookups */
252/** @typedef {WeakMap.<Target, TweenLookups>} TweenReplaceLookups */
253/** @typedef {Map.<Target, TweenLookups>} TweenAdditiveLookups */
254
255// JSAnimation types
256
257/**
258 * @typedef {Number|String|FunctionValue|EasingParam} TweenParamValue
259 */
260
261/**
262 * @typedef {TweenParamValue|[TweenParamValue, TweenParamValue]} TweenPropValue
263 */
264
265/**
266 * @typedef {(String & {})|'none'|'replace'|'blend'|compositionTypes} TweenComposition
267 */
268
269/**
270 * @typedef {Object} TweenParamsOptions
271 * @property {TweenParamValue} [duration]
272 * @property {TweenParamValue} [delay]
273 * @property {EasingParam|FunctionValue} [ease]
274 * @property {TweenModifier} [modifier]
275 * @property {TweenComposition} [composition]
276 */
277
278/**
279 * @typedef {Object} TweenValues
280 * @property {TweenParamValue} [from]
281 * @property {TweenPropValue} [to]
282 * @property {TweenPropValue} [fromTo]
283 */
284
285/**
286 * @typedef {TweenParamsOptions & TweenValues} TweenKeyValue
287 */
288
289/**
290 * @typedef {Array.<TweenKeyValue|TweenPropValue>} ArraySyntaxValue
291 */
292
293/**
294 * @typedef {TweenParamValue|ArraySyntaxValue|TweenKeyValue} TweenOptions
295 */
296
297/**
298 * @typedef {Partial<{to: TweenParamValue|Array.<TweenParamValue>; from: TweenParamValue|Array.<TweenParamValue>; fromTo: TweenParamValue|Array.<TweenParamValue>;}>} TweenObjectValue
299 */
300
301/**
302 * @typedef {Object} PercentageKeyframeOptions
303 * @property {EasingParam} [ease]
304 */
305
306/**
307 * @typedef {Record<String, TweenParamValue>}
307 PercentageKeyframeParams
308 */
309
310/**
311 * @typedef {Record<String, PercentageKeyframeParams & PercentageKeyframeOptions>} PercentageKeyframes
312 */
313
314/**
315 * @typedef {Array<Record<String, TweenOptions | TweenModifier | boolean> & TweenParamsOptions>} DurationKeyframes
316 */
317
318/**
319 * @typedef {Object} AnimationOptions
320 * @property {PercentageKeyframes|DurationKeyframes} [keyframes]
321 * @property {EasingParam} [playbackEase]
322 */
323
324// TODO: Currently setting TweenModifier to the intersected Record<> makes the FunctionValue type target param any if only one parameter is set
325/**
326 * @typedef {Record<String, TweenOptions | Callback<JSAnimation> | TweenModifier | boolean | PercentageKeyframes | DurationKeyframes | ScrollObserver> & TimerOptions & AnimationOptions & TweenParamsOptions & TickableCallbacks<JSAnimation> & RenderableCallbacks<JSAnimation>} AnimationParams
327 */
328
329// Timeline types
330
331/**
332 * Accepts:<br>
333 * - `Number` - Absolute position in milliseconds (e.g., `500` places element at exactly 500ms)<br>
334 * - `'+=Number'` - Addition: Position element X ms after the last element (e.g., `'+=100'`)<br>
335 * - `'-=Number'` - Subtraction: Position element X ms before the last element's end (e.g., `'-=100'`)<br>
336 * - `'*=Number'` - Multiplier: Position element at a fraction of the total duration (e.g., `'*=.5'` for halfway)<br>
337 * - `'<'` - Previous end: Position element at the end position of the previous element<br>
338 * - `'<<'` - Previous start: Position element at the start position of the previous element<br>
339 * - `'<<+=Number'` - Combined: Position element relative to previous element's start (e.g., `'<<+=250'`)<br>
340 * - `'label'` - Label: Position element at a named label position (e.g., `'My Label'`)
341 *
342 * @typedef {Number|`+=${Number}`|`-=${Number}`|`*=${Number}`|'<'|'<<'|`<<+=${Number}`|`<<-=${Number}`|String} TimelinePosition
343 */
344
345/**
346 * Accepts:<br>
347 * - `Number` - Absolute position in milliseconds (e.g., `500` places animation at exactly 500ms)<br>
348 * - `'+=Number'` - Addition: Position animation X ms after the last animation (e.g., `'+=100'`)<br>
349 * - `'-=Number'` - Subtraction: Position animation X ms before the last animation's end (e.g., `'-=100'`)<br>
350 * - `'*=Number'` - Multiplier: Position animation at a fraction of the total duration (e.g., `'*=.5'` for halfway)<br>
351 * - `'<'` - Previous end: Position animation at the end position of the previous animation<br>
352 * - `'<<'` - Previous start: Position animation at the start position of the previous animation<br>
353 * - `'<<+=Number'` - Combined: Position animation relative to previous animation's start (e.g., `'<<+=250'`)<br>
354 * - `'label'` - Label: Position animation at a named label position (e.g., `'My Label'`)<br>
355 * - `stagger(String|Nummber)` - Stagger multi-elements animation positions (e.g., 10, 20, 30...)
356 *
357 * @typedef {TimelinePosition | StaggerFunction<Number|String>} TimelineAnimationPosition
358 */
359
360/**
361 * @typedef {Object} TimelineOptions
362 * @property {DefaultsParams} [defaults]
363 * @property {EasingParam} [playbackEase]
364 * @property {Boolean} [composition]
365 */
366
367/**
368 * @typedef {TimerOptions & TimelineOptions & TickableCallbacks<Timeline> & RenderableCallbacks<Timeline>} TimelineParams
369 */
370
371// WAAPIAnimation types
372
373/**
374 * @typedef {String|Number|Array<String>|Array<Number>} WAAPITweenValue
375 */
376
377/**
378 * @callback WAAPIFunctionValue
379 * @param {DOMTarget} target - The animated target
380 * @param {Number} index - The target index
381 * @param {Number} length - The total number of animated targets
382 * @return {WAAPITweenValue|WAAPIEasingParam}
383 */
384
385/**
386 * @typedef {WAAPITweenValue|WAAPIFunctionValue|Array<String|Number|WAAPIFunctionValue>} WAAPIKeyframeValue
387 */
388
389/**
390 * @typedef {Object} WAAPITweenOptions
391 * @property {WAAPIKeyframeValue} [to]
392 * @property {WAAPIKeyframeValue} [from]
393 * @property {Number|WAAPIFunctionValue} [duration]
394 * @property {Number|WAAPIFunctionValue} [delay]
395 * @property {WAAPIEasingParam} [ease]
396 * @property {CompositeOperation} [composition]
397 */
398
399/**
400 * @typedef {Object} WAAPIAnimationOptions
401 * @property {Number|Boolean} [loop]
402 * @property {Boolean} [Reversed]
403 * @property {Boolean} [Alternate]
404 * @property {Boolean|ScrollObserver} [autoplay]
405 * @property {Number} [playbackRate]
406 * @property {Number|WAAPIFunctionValue} [duration]
407 * @property {Number|WAAPIFunctionValue} [delay]
408 * @property {WAAPIEasingParam|WAAPIFunctionValue} [ease]
409 * @property {CompositeOperation} [composition]
410 * @property {Boolean} [persist]
411 * @property {Callback<WAAPIAnimation>} [onComplete]
412 */
413
414/**
415 * @typedef {Record<String, WAAPIKeyframeValue | WAAPIAnimationOptions | Boolean | ScrollObserver | Callback<WAAPIAnimation> | WAAPIEasingParam | WAAPITweenOptions> & WAAPIAnimationOptions} WAAPIAnimationParams
416 */
417
418// Animatable types
419
420/**
421 * @callback AnimatablePropertySetter
422 * @param  {Number|Array.<Number>} to
423 * @param  {Number} [duration]
424 * @param  {EasingParam} [ease]
425 * @return {AnimatableObject}
426 */
427
428/**
429 * @callback AnimatablePropertyGetter
430 * @return {Number|Array.<Number>}
431 */
432
433/**
434 * @typedef {AnimatablePropertySetter & AnimatablePropertyGetter} AnimatableProperty
435 */
436
437/**
438 * @typedef {Animatable & Record<String, AnimatableProperty>} AnimatableObject
439 */
440
441/**
442 * @typedef {Object} AnimatablePropertyParamsOptions
443 * @property {String} [unit]
444 * @property {TweenParamValue} [duration]
445 * @property {EasingParam} [ease]
446 * @property {TweenModifier} [modifier]
447 * @property {TweenComposition} [composition]
448 */
449
450/**
451 * @typedef {Record<String, TweenParamValue | EasingParam | TweenModifier | TweenComposition | AnimatablePropertyParamsOptions> & AnimatablePropertyParamsOptions} AnimatableParams
452 */
453
454// Scope types
455
456/**
457 * @typedef {Object} ReactRef
458 * @property {HTMLElement|SVGElement|null} [current]
459 */
460
461/**
462 * @typedef {Object} AngularRef
463 * @property {HTMLElement|SVGElement} [nativeElement]
464 */
465
466/**
467 * @typedef {Object} ScopeParams
468 * @property {DOMTargetSelector|ReactRef|AngularRef} [root]
469 * @property {DefaultsParams} [defaults]
470 * @property {Record<String, String>} [mediaQueries]
471 */
472
473/**
474 * @template T
475 * @callback ScopedCallback
476 * @param {Scope} scope
477 * @return {T}
478 */
479
480/**
481 * @callback ScopeCleanupCallback
482 * @param {Scope} [scope]
483 */
484
485/**
486 * @callback ScopeConstructorCallback
487 * @param {Scope} [scope]
488 * @return {ScopeCleanupCallback|void}
489 */
490
491/**
492 * @callback ScopeMethod
493 * @param {...*} args
494 * @return {ScopeCleanupCallback|void}
495 */
496
497// Scroll types
498
499/**
500 * @typedef {String|Number} ScrollThresholdValue
501 */
502
503/**
504 * @typedef {Object} ScrollThresholdParam
505 * @property {ScrollThresholdValue} [target]
506 * @property {ScrollThresholdValue} [container]
507 */
508
509/**
510 * @callback ScrollObserverAxisCallback
511 * @param {ScrollObserver} self
512 * @return {'x'|'y'}
513 */
514
515/**
516 * @callback ScrollThresholdCallback
517 * @param {ScrollObserver} self
518 * @return {ScrollThresholdValue|ScrollThresholdParam}
519 */
520
521/**
522 * @typedef {Object} ScrollObserverParams
523 * @property {Number|String} [id]
524 * @property {Boolean|Number|String|EasingParam} [sync]
525 * @property {TargetsParam} [container]
526 * @property {TargetsParam} [target]
527 * @property {'x'|'y'|ScrollObserverAxisCallback|((observer: ScrollObserver) => 'x'|'y'|ScrollObserverAxisCallback)} [axis]
528 * @property {ScrollThresholdValue|ScrollThresholdParam|ScrollThresholdCallback|((observer: ScrollObserver) => ScrollThresholdValue|ScrollThresholdParam|ScrollThresholdCallback)} [enter]
529 * @property {ScrollThresholdValue|ScrollThresholdParam|ScrollThresholdCallback|((observer: ScrollObserver) => ScrollThresholdValue|ScrollThresholdParam|ScrollThresholdCallback)} [leave]
530 * @property {Boolean|((observer: ScrollObserver) => Boolean)} [repeat]
531 * @property {Boolean} [debug]
532 * @property {Callback<ScrollObserver>} [onEnter]
533 * @property {Callback<ScrollObserver>} [onLeave]
534 * @property {Callback<ScrollObserver>} [onEnterForward]
535 * @property {Callback<ScrollObserver>} [onLeaveForward]
536 * @property {Callback<ScrollObserver>} [onEnterBackward]
537 * @property {Callback<ScrollObserver>} [onLeaveBackward]
538 * @property {Callback<ScrollObserver>} [onUpdate]
539 * @property {Callback<ScrollObserver>} [onSyncComplete]
540 */
541
542// Draggable types
543
544/**
545 * @typedef {Object} DraggableAxisParam
546 * @property {String} [mapTo]
547 * @property {TweenModifier} [modifier]
548 * @property {TweenComposition} [composition]
549 * @property {Number|Array<Number>|((draggable: Draggable) => Number|Array<Number>)} [snap]
550 */
551
552/**
553 * @typedef {Object} DraggableCursorParams
554 * @property {String} [onHover]
555 * @property {String} [onGrab]
556 */
557
558/**
559 * @typedef {Object} DraggableDragThresholdParams
560 * @property {Number} [mouse]
561 * @property {Number} [touch]
562 */
563
vendor: 8,671 bytes, lines 564-854
564/**
565 * @typedef {Object} DraggableParams
566 * @property {DOMTargetSelector} [trigger]
567 * @property {DOMTargetSelector|Array<Number>|((draggable: Draggable) => DOMTargetSelector|Array<Number>)} [container]
568 * @property {Boolean|DraggableAxisParam} [x]
569 * @property {Boolean|DraggableAxisParam} [y]
570 * @property {TweenModifier} [modifier]
571 * @property {Number|Array<Number>|((draggable: Draggable) => Number|Array<Number>)} [snap]
572 * @property {Number|Array<Number>|((draggable: Draggable) => Number|Array<Number>)} [containerPadding]
573 * @property {Number|((draggable: Draggable) => Number)} [containerFriction]
574 * @property {Number|((draggable: Draggable) => Number)} [releaseContainerFriction]
575 * @property {Number|((draggable: Draggable) => Number)} [dragSpeed]
576 * @property {Number|DraggableDragThresholdParams|((draggable: Draggable) => Number|DraggableDragThresholdParams)} [dragThreshold]
577 * @property {Number|((draggable: Draggable) => Number)} [scrollSpeed]
578 * @property {Number|((draggable: Draggable) => Number)} [scrollThreshold]
579 * @property {Number|((draggable: Draggable) => Number)} [minVelocity]
580 * @property {Number|((draggable: Draggable) => Number)} [maxVelocity]
581 * @property {Number|((draggable: Draggable) => Number)} [velocityMultiplier]
582 * @property {Number} [releaseMass]
583 * @property {Number} [releaseStiffness]
584 * @property {Number} [releaseDamping]
585 * @property {Boolean} [releaseDamping]
586 * @property {EasingParam} [releaseEase]
587 * @property {Boolean|DraggableCursorParams|((draggable: Draggable) => Boolean|DraggableCursorParams)} [cursor]
588 * @property {Callback<Draggable>} [onGrab]
589 * @property {Callback<Draggable>} [onDrag]
590 * @property {Callback<Draggable>} [onRelease]
591 * @property {Callback<Draggable>} [onUpdate]
592 * @property {Callback<Draggable>} [onSettle]
593 * @property {Callback<Draggable>} [onSnap]
594 * @property {Callback<Draggable>} [onResize]
595 * @property {Callback<Draggable>} [onAfterResize]
596 */
597
598// Text types
599
600/**
601 * @typedef {Object} SplitTemplateParams
602 * @property {false|String} [class]
603 * @property {Boolean|'hidden'|'clip'|'visible'|'scroll'|'auto'} [wrap]
604 * @property {Boolean|'top'|'right'|'bottom'|'left'|'center'} [clone]
605 */
606
607/**
608 * @typedef {Boolean|String} SplitValue
609 */
610
611/**
612 * @callback SplitFunctionValue
613 * @param {Node|HTMLElement} [value]
614 * @return String
615 */
616
617/**
618 * @typedef {Object} TextSplitterParams
619 * @property {SplitValue|SplitTemplateParams|SplitFunctionValue} [lines]
620 * @property {SplitValue|SplitTemplateParams|SplitFunctionValue} [words]
621 * @property {SplitValue|SplitTemplateParams|SplitFunctionValue} [chars]
622 * @property {Boolean} [accessible]
623 * @property {Boolean} [includeSpaces]
624 * @property {Boolean} [debug]
625 */
626
627// SVG types
628
629/**
630 * @typedef {SVGGeometryElement & {
631 *   setAttribute(name: 'draw', value: `${number} ${number}`): void;
632 *   draw: `${number} ${number}`;
633 * }} DrawableSVGGeometry
634 */
635
636
637(function (global, factory) {
638  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
639  typeof define === 'function' && define.amd ? define(['exports'], factory) :
640  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.anime = {}));
641})(this, (function (exports) { 'use strict';
642
643  // Environments
644
645  // TODO: Do we need to check if we're running inside a worker ?
646  const isBrowser = typeof window !== 'undefined';
647
648  /** @typedef {Window & {AnimeJS: Array} & {AnimeJSDevTools: any}|null} AnimeJSWindow
649
650  /** @type {AnimeJSWindow} */
651  const win = isBrowser ? /** @type {AnimeJSWindow} */(/** @type {unknown} */(window)) : null;
652
653  /** @type {Document|null} */
654  const doc = isBrowser ? document : null;
655
656  // Enums
657
658  /** @enum {Number} */
659  const tweenTypes = {
660    OBJECT: 0,
661    ATTRIBUTE: 1,
662    CSS: 2,
663    TRANSFORM: 3,
664    CSS_VAR: 4,
665  };
666
667  /** @enum {Number} */
668  const valueTypes = {
669    NUMBER: 0,
670    UNIT: 1,
671    COLOR: 2,
672    COMPLEX: 3,
673  };
674
675  /** @enum {Number} */
676  const tickModes = {
677    NONE: 0,
678    AUTO: 1,
679    FORCE: 2,
680  };
681
682  /** @enum {Number} */
683  const compositionTypes = {
684    replace: 0,
685    none: 1,
686    blend: 2,
687  };
688
689  // Cache symbols
690
691  const isRegisteredTargetSymbol = Symbol();
692  const isDomSymbol = Symbol();
693  const isSvgSymbol = Symbol();
694  const transformsSymbol = Symbol();
695  const morphPointsSymbol = Symbol();
696  const proxyTargetSymbol = Symbol();
697
698  // Numbers
699
700  const minValue = 1e-11;
701  const maxValue = 1e12;
702  const K = 1e3;
703  const maxFps = 240;
704
705  // Strings
706
707  const emptyString = '';
708  const cssVarPrefix = 'var(';
709
710  const shortTransforms = /*#__PURE__*/ (() => {
711    const map = new Map();
712    map.set('x', 'translateX');
713    map.set('y', 'translateY');
714    map.set('z', 'translateZ');
715    return map;
716  })();
717
718  const validTransforms = [
719    'translateX',
720    'translateY',
721    'translateZ',
722    'rotate',
723    'rotateX',
724    'rotateY',
725    'rotateZ',
726    'scale',
727    'scaleX',
728    'scaleY',
729    'scaleZ',
730    'skew',
731    'skewX',
732    'skewY',
733    'matrix',
734    'matrix3d',
735    'perspective',
736  ];
737
738  const transformsFragmentStrings = /*#__PURE__*/ validTransforms.reduce((a, v) => ({...a, [v]: v + '('}), {});
739
740  // Functions
741
742  /** @return {void} */
743  const noop = () => {};
744
745  // Regex
746
747  const hexTestRgx = /(^#([\da-f]{3}){1,2}$)|(^#([\da-f]{4}){1,2}$)/i;
748  const rgbExecRgx = /rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i;
749  const rgbaExecRgx = /rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(-?\d+|-?\d*.\d+)\s*\)/i;
750  const hslExecRgx = /hsl\(\s*(-?\d+|-?\d*.\d+)\s*,\s*(-?\d+|-?\d*.\d+)%\s*,\s*(-?\d+|-?\d*.\d+)%\s*\)/i;
751  const hslaExecRgx = /hsla\(\s*(-?\d+|-?\d*.\d+)\s*,\s*(-?\d+|-?\d*.\d+)%\s*,\s*(-?\d+|-?\d*.\d+)%\s*,\s*(-?\d+|-?\d*.\d+)\s*\)/i;
752  // export const digitWithExponentRgx = /[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?/g;
753  const digitWithExponentRgx = /[-+]?\d*\.?\d+(?:e[-+]?\d)?/gi;
754  // export const unitsExecRgx = /^([-+]?\d*\.?\d+(?:[eE][-+]?\d+)?)+([a-z]+|%)$/i;
755  const unitsExecRgx = /^([-+]?\d*\.?\d+(?:e[-+]?\d+)?)([a-z]+|%)$/i;
756  const lowerCaseRgx = /([a-z])([A-Z])/g;
757  const transformsExecRgx = /(\w+)(\([^)]+\)+)/g; // Match inline transforms with cacl() values, returns the value wrapped in ()
758  const relativeValuesExecRgx = /(\*=|\+=|-=)/;
759  const cssVariableMatchRgx = /var\(\s*(--[\w-]+)(?:\s*,\s*([^)]+))?\s*\)/;
760
761  
762
763  /** @type {DefaultsParams} */
764  const defaults = {
765    id: null,
766    keyframes: null,
767    playbackEase: null,
768    playbackRate: 1,
769    frameRate: maxFps,
770    loop: 0,
771    reversed: false,
772    alternate: false,
773    autoplay: true,
774    persist: false,
775    duration: K,
776    delay: 0,
777    loopDelay: 0,
778    ease: 'out(2)',
779    composition: compositionTypes.replace,
780    modifier: v => v,
781    onBegin: noop,
782    onBeforeUpdate: noop,
783    onUpdate: noop,
784    onLoop: noop,
785    onPause: noop,
786    onComplete: noop,
787    onRender: noop,
788  };
789
790  const scope = {
791    /** @type {Scope} */
792    current: null,
793    /** @type {Document|DOMTarget} */
794    root: doc,
795  };
796
797  const globals = {
798    /** @type {DefaultsParams} */
799    defaults,
800    /** @type {Number} */
801    precision: 4,
802    /** @type {Number} equals 1 in ms mode, 0.001 in s mode */
803    timeScale: 1,
804    /** @type {Number} */
805    tickThreshold: 200,
806  };
807
808  const devTools = isBrowser && win.AnimeJSDevTools;
809
810  const globalVersions = { version: '4.3.2', engine: null };
811
812  if (isBrowser) {
813    if (!win.AnimeJS) win.AnimeJS = [];
814    win.AnimeJS.push(globalVersions);
815  }
816
817  
818
819  // Strings
820
821  /**
822   * @param  {String} str
823   * @return {String}
824   */
825  const toLowerCase = str => str.replace(lowerCaseRgx, '$1-$2').toLowerCase();
826
827  /**
828   * Prioritize this method instead of regex when possible
829   * @param  {String} str
830   * @param  {String} sub
831   * @return {Boolean}
832   */
833  const stringStartsWith = (str, sub) => str.indexOf(sub) === 0;
834
835  // 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.
836  const now = Date.now;
837
838  // Types checkers
839
840  const isArr = Array.isArray;
841  /**@param {any} a @return {a is Record<String, any>} */
842  const isObj = a => a && a.constructor === Object;
843  /**@param {any} a @return {a is Number} */
844  const isNum = a => typeof a === 'number' && !isNaN(a);
845  /**@param {any} a @return {a is String} */
846  const isStr = a => typeof a === 'string';
847  /**@param {any} a @return {a is Function} */
848  const isFnc = a => typeof a === 'function';
849  /**@param {any} a @return {a is undefined} */
850  const isUnd = a => typeof a === 'undefined';
851  /**@param {any} a @return {a is null | undefined} */
852  const isNil = a => isUnd(a) || a === null;
853  /**@param {any} a @return {a is SVGElement} */
854  const isSvg = a =>
854 isBrowser && a instanceof SVGElement;
855  /**@param {any} a @return {Boolean} */
856  const isHex = a => hexTestRgx.test(a);
857  /**@param {any} a @return {Boolean} */
858  const isRgb = a => stringStartsWith(a, 'rgb') && a[a.length - 1] === ')';
859  /**@param {any} a @return {Boolean} */
860  const isHsl = a => stringStartsWith(a, 'hsl') && a[a.length - 1] === ')';
861  /**@param {any} a @return {Boolean} */
862  const isCol = a => isHex(a) || isRgb(a) || isHsl(a);
863  /**@param {any} a @return {Boolean} */
864  const isKey = a => !globals.defaults.hasOwnProperty(a);
865
866  // SVG
867
868  // Consider the following as CSS animation
869  // CSS opacity animation has better default values (opacity: 1 instead of 0))
870  // rotate is more commonly intended to be used as a transform
871  const svgCssReservedProperties = ['opacity', 'rotate', 'overflow', 'color'];
872
873  /**
874   * @param  {Target} el
875   * @param  {String} propertyName
876   * @return {Boolean}
877   */
878  const isValidSVGAttribute = (el, propertyName) => {
879    if (svgCssReservedProperties.includes(propertyName)) return false;
880    if (el.getAttribute(propertyName) || propertyName in el) {
881      if (propertyName === 'scale') { // Scale
882        const elParentNode = /** @type {SVGGeometryElement} */(/** @type {DOMTarget} */(el).parentNode);
883        // Only consider scale as a valid SVG attribute on filter element
884        return elParentNode && elParentNode.tagName === 'filter';
885      }
886      return true;
887    }
888  };
889
890  // Number
891
892  /**
893   * @param  {Number|String} str
894   * @return {Number}
895   */
896  const parseNumber = str => isStr(str) ?
897    parseFloat(/** @type {String} */(str)) :
898    /** @type {Number} */(str);
899
900  // Math
901
902  const pow = Math.pow;
903  const sqrt = Math.sqrt;
904  const sin = Math.sin;
905  const cos = Math.cos;
906  const abs = Math.abs;
907  const exp = Math.exp;
908  const ceil = Math.ceil;
909  const floor = Math.floor;
910  const asin = Math.asin;
911  const max = Math.max;
912  const atan2 = Math.atan2;
913  const PI = Math.PI;
914  const _round = Math.round;
915
916  /**
917   * Clamps a value between min and max bounds
918   *
919   * @param  {Number} v - Value to clamp
920   * @param  {Number} min - Minimum boundary
921   * @param  {Number} max - Maximum boundary
922   * @return {Number}
923   */
924  const clamp$1 = (v, min, max) => v < min ? min : v > max ? max : v;
925
926  const powCache = {};
927
928  /**
929   * Rounds a number to specified decimal places
930   *
931   * @param  {Number} v - Value to round
932   * @param  {Number} decimalLength - Number of decimal places
933   * @return {Number}
934   */
935  const round$1 = (v, decimalLength) => {
936    if (decimalLength < 0) return v;
937    if (!decimalLength) return _round(v);
938    let p = powCache[decimalLength];
939    if (!p) p = powCache[decimalLength] = 10 ** decimalLength;
940    return _round(v * p) / p;
941  };
942
943  /**
944   * Snaps a value to nearest increment or array value
945   *
946   * @param  {Number} v - Value to snap
947   * @param  {Number|Array<Number>} increment - Step size or array of snap points
948   * @return {Number}
949   */
950  const snap$1 = (v, increment) => isArr(increment) ? increment.reduce((closest, cv) => (abs(cv - v) < abs(closest - v) ? cv : closest)) : increment ? _round(v / increment) * increment : v;
951
952  /**
953   * Linear interpolation between two values
954   *
955   * @param  {Number} start - Starting value
956   * @param  {Number} end - Ending value
957   * @param  {Number} factor - Interpolation factor in the range [0, 1]
958   * @return {Number} The interpolated value
959   */
960  const lerp$1 = (start, end, factor) => start + (end - start) * factor;
961
962  /**
963   * Replaces infinity with maximum safe value
964   *
965   * @param  {Number} v - Value to check
966   * @return {Number}
967   */
968  const clampInfinity = v => v === Infinity ? maxValue : v === -Infinity ? -maxValue : v;
969
970  /**
971   * Normalizes time value with minimum threshold
972   *
973   * @param  {Number} v - Time value to normalize
974   * @return {Number}
975   */
976  const normalizeTime = v => v <= minValue ? minValue : clampInfinity(round$1(v, 11));
977
978  // Arrays
979
980  /**
981   * @template T
982   * @param    {T[]} a
983   * @return   {T[]}
984   */
985  const cloneArray = a => isArr(a) ? [ ...a ] : a;
986
987  // Objects
988
989  /**
990   * @template T
991   * @template U
992   * @param    {T} o1
993   * @param    {U} o2
994   * @return   {T & U}
995   */
996  const mergeObjects = (o1, o2) => {
997    const merged = /** @type {T & U} */({ ...o1 });
998    for (let p in o2) {
999      const o1p = /** @type {T & U} */(o1)[p];
1000      merged[p] = isUnd(o1p) ? /** @type {T & U} */(o2)[p] : o1p;
1001    }  return merged;
1002  };
1003
1004  // Linked lists
1005
1006  /**
1007   * @param  {Object} parent
1008   * @param  {Function} callback
1009   * @param  {Boolean} [reverse]
1010   * @param  {String} [prevProp]
1011   * @param  {String} [nextProp]
1012   * @return {void}
1013   */
vendor: 4,788 bytes, lines 1014-1167
1014  const forEachChildren = (parent, callback, reverse, prevProp = '_prev', nextProp = '_next') => {
1015    let next = parent._head;
1016    let adjustedNextProp = nextProp;
1017    if (reverse) {
1018      next = parent._tail;
1019      adjustedNextProp = prevProp;
1020    }
1021    while (next) {
1022      const currentNext = next[adjustedNextProp];
1023      callback(next);
1024      next = currentNext;
1025    }
1026  };
1027
1028  /**
1029   * @param  {Object} parent
1030   * @param  {Object} child
1031   * @param  {String} [prevProp]
1032   * @param  {String} [nextProp]
1033   * @return {void}
1034   */
1035  const removeChild = (parent, child, prevProp = '_prev', nextProp = '_next') => {
1036    const prev = child[prevProp];
1037    const next = child[nextProp];
1038    prev ? prev[nextProp] = next : parent._head = next;
1039    next ? next[prevProp] = prev : parent._tail = prev;
1040    child[prevProp] = null;
1041    child[nextProp] = null;
1042  };
1043
1044  /**
1045   * @param  {Object} parent
1046   * @param  {Object} child
1047   * @param  {Function} [sortMethod]
1048   * @param  {String} prevProp
1049   * @param  {String} nextProp
1050   * @return {void}
1051   */
1052  const addChild = (parent, child, sortMethod, prevProp = '_prev', nextProp = '_next') => {
1053    let prev = parent._tail;
1054    while (prev && sortMethod && sortMethod(prev, child)) prev = prev[prevProp];
1055    const next = prev ? prev[nextProp] : parent._head;
1056    prev ? prev[nextProp] = child : parent._head = child;
1057    next ? next[prevProp] = child : parent._tail = child;
1058    child[prevProp] = prev;
1059    child[nextProp] = next;
1060  };
1061
1062  
1063
1064  /**
1065   * @param  {DOMTarget} target
1066   * @param  {String} propName
1067   * @param  {Object} animationInlineStyles
1068   * @return {String}
1069   */
1070  const parseInlineTransforms = (target, propName, animationInlineStyles) => {
1071    const inlineTransforms = target.style.transform;
1072    let inlinedStylesPropertyValue;
1073    if (inlineTransforms) {
1074      const cachedTransforms = target[transformsSymbol];
1075      let t; while (t = transformsExecRgx.exec(inlineTransforms)) {
1076        const inlinePropertyName = t[1];
1077        // const inlinePropertyValue = t[2];
1078        const inlinePropertyValue = t[2].slice(1, -1);
1079        cachedTransforms[inlinePropertyName] = inlinePropertyValue;
1080        if (inlinePropertyName === propName) {
1081          inlinedStylesPropertyValue = inlinePropertyValue;
1082          // Store the new parsed inline styles if animationInlineStyles is provided
1083          if (animationInlineStyles) {
1084            animationInlineStyles[propName] = inlinePropertyValue;
1085          }
1086        }
1087      }
1088    }
1089    return inlineTransforms && !isUnd(inlinedStylesPropertyValue) ? inlinedStylesPropertyValue :
1090      stringStartsWith(propName, 'scale') ? '1' :
1091      stringStartsWith(propName, 'rotate') || stringStartsWith(propName, 'skew') ? '0deg' : '0px';
1092  };
1093
1094  
1095
1096  /**
1097   * RGB / RGBA Color value string -> RGBA values array
1098   * @param  {String} rgbValue
1099   * @return {ColorArray}
1100   */
1101  const rgbToRgba = rgbValue => {
1102    const rgba = rgbExecRgx.exec(rgbValue) || rgbaExecRgx.exec(rgbValue);
1103    const a = !isUnd(rgba[4]) ? +rgba[4] : 1;
1104    return [
1105      +rgba[1],
1106      +rgba[2],
1107      +rgba[3],
1108      a
1109    ]
1110  };
1111
1112  /**
1113   * HEX3 / HEX3A / HEX6 / HEX6A Color value string -> RGBA values array
1114   * @param  {String} hexValue
1115   * @return {ColorArray}
1116   */
1117  const hexToRgba = hexValue => {
1118    const hexLength = hexValue.length;
1119    const isShort = hexLength === 4 || hexLength === 5;
1120    return [
1121      +('0x' + hexValue[1] + hexValue[isShort ? 1 : 2]),
1122      +('0x' + hexValue[isShort ? 2 : 3] + hexValue[isShort ? 2 : 4]),
1123      +('0x' + hexValue[isShort ? 3 : 5] + hexValue[isShort ? 3 : 6]),
1124      ((hexLength === 5 || hexLength === 9) ? +(+('0x' + hexValue[isShort ? 4 : 7] + hexValue[isShort ? 4 : 8]) / 255).toFixed(3) : 1)
1125    ]
1126  };
1127
1128  /**
1129   * @param  {Number} p
1130   * @param  {Number} q
1131   * @param  {Number} t
1132   * @return {Number}
1133   */
1134  const hue2rgb = (p, q, t) => {
1135    if (t < 0) t += 1;
1136    if (t > 1) t -= 1;
1137    return t < 1 / 6 ? p + (q - p) * 6 * t :
1138           t < 1 / 2 ? q :
1139           t < 2 / 3 ? p + (q - p) * (2 / 3 - t) * 6 :
1140           p;
1141  };
1142
1143  /**
1144   * HSL / HSLA Color value string -> RGBA values array
1145   * @param  {String} hslValue
1146   * @return {ColorArray}
1147   */
1148  const hslToRgba = hslValue => {
1149    const hsla = hslExecRgx.exec(hslValue) || hslaExecRgx.exec(hslValue);
1150    const h = +hsla[1] / 360;
1151    const s = +hsla[2] / 100;
1152    const l = +hsla[3] / 100;
1153    const a = !isUnd(hsla[4]) ? +hsla[4] : 1;
1154    let r, g, b;
1155    if (s === 0) {
1156      r = g = b = l;
1157    } else {
1158      const q = l < .5 ? l * (1 + s) : l + s - l * s;
1159      const p = 2 * l - q;
1160      r = round$1(hue2rgb(p, q, h + 1 / 3) * 255, 0);
1161      g = round$1(hue2rgb(p, q, h) * 255, 0);
1162      b = round$1(hue2rgb(p, q, h - 1 / 3) * 255, 0);
1163    }
1164    return [r, g, b, a];
1165  };
1166
1167  /**
1168   * All in one color converter that converts a color string value into an array of RGBA values
1169   * @param  {String} colorString
1170   * @return {ColorArray}
1171   */
1172  const convertColorStringValuesToRgbaArray = colorString => {
1173    return isRgb(colorString) ? rgbToRgba(colorString) :
1174           isHex(colorString) ? hexToRgba(colorString) :
1175           isHsl(colorString) ? hslToRgba(colorString) :
1176           [0, 0, 0, 1];
1177  };
1178
1179  
1180
1181  /**
1182   * @template T, D
1183   * @param {T|undefined} targetValue
1184   * @param {D} defaultValue
1185   * @return {T|D}
1186   */
1187  const setValue = (targetValue, defaultValue) => {
1188    return isUnd(targetValue) ? defaultValue : targetValue;
1189  };
1190
1191  /**
1192   * @param  {TweenPropValue} value
1193   * @param  {Target} target
1194   * @param  {Number} index
1195   * @param  {Number} total
1196   * @param  {Object} [store]
1197   * @return {any}
1198   */
1199  const getFunctionValue = (value, target, index, total, store) => {
1200    let func;
1201    if (isFnc(value)) {
1202      func = () => {
1203        const computed = /** @type {Function} */(value)(target, index, total);
1204        // Fallback to 0 if the function returns undefined / NaN / null / false / 0
1205        return !isNaN(+computed) ? +computed : computed || 0;
1206      };
1207    } else if (isStr(value) && stringStartsWith(value, cssVarPrefix)) {
1208      func = () => {
1209        const match = value.match(cssVariableMatchRgx);
1210        const cssVarName = match[1];
1211        const fallbackValue = match[2];
1212        let computed = getComputedStyle(/** @type {HTMLElement} */(target))?.getPropertyValue(cssVarName);
1213        // Use fallback if CSS variable is not set or empty
1214        if ((!computed || computed.trim() === emptyString) && fallbackValue) {
1215          computed = fallbackValue.trim();
1216        }
1217        return computed || 0;
1218      };
1219    } else {
1220      return value;
1221    }
1222    if (store) store.func = func;
1223    return func();
1224  };
1225
1226  /**
1227   * @param  {Target} target
1228   * @param  {String} prop
1229   * @return {tweenTypes}
1230   */
1231  const getTweenType = (target, prop) => {
1232    return !target[isDomSymbol] ? tweenTypes.OBJECT :
1233      // Handle SVG attributes
1234      target[isSvgSymbol] && isValidSVGAttribute(target, prop) ? tweenTypes.ATTRIBUTE :
1235      // Handle CSS Transform properties differently than CSS to allow individual animations
1236      validTransforms.includes(prop) || shortTransforms.get(prop) ? tweenTypes.TRANSFORM :
1237      // CSS variables
1238      stringStartsWith(prop, '--') ? tweenTypes.CSS_VAR :
1239      // All other CSS properties
1240      prop in /** @type {DOMTarget} */(target).style ? tweenTypes.CSS :
1241      // Handle other DOM Attributes
1242      prop in target ? tweenTypes.OBJECT :
1243      tweenTypes.ATTRIBUTE;
1244  };
1245
1246  /**
1247   * @param  {DOMTarget} target
1248   * @param  {String} propName
1249   * @param  {Object} animationInlineStyles
1250   * @return {String}
1251   */
1252  const getCSSValue = (target, propName, animationInlineStyles) => {
1253    const inlineStyles = target.style[propName];
1254    if (inlineStyles && animationInlineStyles) {
1255      animationInlineStyles[propName] = inlineStyles;
1256    }
1257    const value = inlineStyles || getComputedStyle(target[proxyTargetSymbol] || target).getPropertyValue(propName);
1258    return value === 'auto' ? '0' : value;
1259  };
1260
1261  /**
1262   * @param {Target} target
1263   * @param {String} propName
1264   * @param {tweenTypes} [tweenType]
1265   * @param {Object|void} [animationInlineStyles]
1266   * @return {String|Number}
1267   */
1268  const getOriginalAnimatableValue = (target, propName, tweenType, animationInlineStyles) => {
1269    const type = !isUnd(tweenType) ? tweenType : getTweenType(target, propName);
1270    return type === tweenTypes.OBJECT ? target[propName] || 0 :
1271           type === tweenTypes.ATTRIBUTE ? /** @type {DOMTarget} */(target).getAttribute(propName) :
1272           type === tweenTypes.TRANSFORM ? parseInlineTransforms(/** @type {DOMTarget} */(target), propName, animationInlineStyles) :
1273           type === tweenTypes.CSS_VAR ? getCSSValue(/** @type {DOMTarget} */(target), propName, animationInlineStyles).trimStart() :
1274           getCSSValue(/** @type {DOMTarget} */(target), propName, animationInlineStyles);
1275  };
1276
1277  /**
1278   * @param  {Number} x
1279   * @param  {Number} y
1280   * @param  {String} operator
vendor: 29,362 bytes, lines 1281-1995
1281   * @return {Number}
1282   */
1283  const getRelativeValue = (x, y, operator) => {
1284    return operator === '-' ? x - y :
1285           operator === '+' ? x + y :
1286           x * y;
1287  };
1288
1289  /** @return {TweenDecomposedValue} */
1290  const createDecomposedValueTargetObject = () => {
1291    return {
1292      /** @type {valueTypes} */
1293      t: valueTypes.NUMBER,
1294      n: 0,
1295      u: null,
1296      o: null,
1297      d: null,
1298      s: null,
1299    }
1300  };
1301
1302  /**
1303   * @param  {String|Number} rawValue
1304   * @param  {TweenDecomposedValue} targetObject
1305   * @return {TweenDecomposedValue}
1306   */
1307  const decomposeRawValue = (rawValue, targetObject) => {
1308    /** @type {valueTypes} */
1309    targetObject.t = valueTypes.NUMBER;
1310    targetObject.n = 0;
1311    targetObject.u = null;
1312    targetObject.o = null;
1313    targetObject.d = null;
1314    targetObject.s = null;
1315    if (!rawValue) return targetObject;
1316    const num = +rawValue;
1317    if (!isNaN(num)) {
1318      // It's a number
1319      targetObject.n = num;
1320      return targetObject;
1321    } else {
1322      // let str = /** @type {String} */(rawValue).trim();
1323      let str = /** @type {String} */(rawValue);
1324      // Parsing operators (+=, -=, *=) manually is much faster than using regex here
1325      if (str[1] === '=') {
1326        targetObject.o = str[0];
1327        str = str.slice(2);
1328      }
1329      // Skip exec regex if the value type is complex or color to avoid long regex backtracking
1330      const unitMatch = str.includes(' ') ? false : unitsExecRgx.exec(str);
1331      if (unitMatch) {
1332        // Has a number and a unit
1333        targetObject.t = valueTypes.UNIT;
1334        targetObject.n = +unitMatch[1];
1335        targetObject.u = unitMatch[2];
1336        return targetObject;
1337      } else if (targetObject.o) {
1338        // Has an operator (+=, -=, *=)
1339        targetObject.n = +str;
1340        return targetObject;
1341      } else if (isCol(str)) {
1342        // Is a color
1343        targetObject.t = valueTypes.COLOR;
1344        targetObject.d = convertColorStringValuesToRgbaArray(str);
1345        return targetObject;
1346      } else {
1347        // Is a more complex string (generally svg coords, calc() or filters CSS values)
1348        const matchedNumbers = str.match(digitWithExponentRgx);
1349        targetObject.t = valueTypes.COMPLEX;
1350        targetObject.d = matchedNumbers ? matchedNumbers.map(Number) : [];
1351        targetObject.s = str.split(digitWithExponentRgx) || [];
1352        return targetObject;
1353      }
1354    }
1355  };
1356
1357  /**
1358   * @param  {Tween} tween
1359   * @param  {TweenDecomposedValue} targetObject
1360   * @return {TweenDecomposedValue}
1361   */
1362  const decomposeTweenValue = (tween, targetObject) => {
1363    targetObject.t = tween._valueType;
1364    targetObject.n = tween._toNumber;
1365    targetObject.u = tween._unit;
1366    targetObject.o = null;
1367    targetObject.d = cloneArray(tween._toNumbers);
1368    targetObject.s = cloneArray(tween._strings);
1369    return targetObject;
1370  };
1371
1372  const decomposedOriginalValue = createDecomposedValueTargetObject();
1373
1374  
1375
1376  
1377
1378  
1379
1380  /**
1381   * @param  {Tickable} tickable
1382   * @param  {Number} time
1383   * @param  {Number} muteCallbacks
1384   * @param  {Number} internalRender
1385   * @param  {tickModes} tickMode
1386   * @return {Number}
1387   */
1388  const render = (tickable, time, muteCallbacks, internalRender, tickMode) => {
1389
1390    const parent = tickable.parent;
1391    const duration = tickable.duration;
1392    const completed = tickable.completed;
1393    const iterationDuration = tickable.iterationDuration;
1394    const iterationCount = tickable.iterationCount;
1395    const _currentIteration = tickable._currentIteration;
1396    const _loopDelay = tickable._loopDelay;
1397    const _reversed = tickable._reversed;
1398    const _alternate = tickable._alternate;
1399    const _hasChildren = tickable._hasChildren;
1400    const tickableDelay = tickable._delay;
1401    const tickablePrevAbsoluteTime = tickable._currentTime; // TODO: rename ._currentTime to ._absoluteCurrentTime
1402
1403    const tickableEndTime = tickableDelay + iterationDuration;
1404    const tickableAbsoluteTime = time - tickableDelay;
1405    const tickablePrevTime = clamp$1(tickablePrevAbsoluteTime, -tickableDelay, duration);
1406    const tickableCurrentTime = clamp$1(tickableAbsoluteTime, -tickableDelay, duration);
1407    const deltaTime = tickableAbsoluteTime - tickablePrevAbsoluteTime;
1408    const isCurrentTimeAboveZero = tickableCurrentTime > 0;
1409    const isCurrentTimeEqualOrAboveDuration = tickableCurrentTime >= duration;
1410    const isSetter = duration <= minValue;
1411    const forcedTick = tickMode === tickModes.FORCE;
1412
1413    let isOdd = 0;
1414    let iterationElapsedTime = tickableAbsoluteTime;
1415    // Render checks
1416    // Used to also check if the children have rendered in order to trigger the onRender callback on the parent timer
1417    let hasRendered = 0;
1418
1419    // Execute the "expensive" iterations calculations only when necessary
1420    if (iterationCount > 1) {
1421      // bitwise NOT operator seems to be generally faster than Math.floor() across browsers
1422      const currentIteration = ~~(tickableCurrentTime / (iterationDuration + (isCurrentTimeEqualOrAboveDuration ? 0 : _loopDelay)));
1423      tickable._currentIteration = clamp$1(currentIteration, 0, iterationCount);
1424      // Prevent the iteration count to go above the max iterations when reaching the end of the animation
1425      if (isCurrentTimeEqualOrAboveDuration) tickable._currentIteration--;
1426      isOdd = tickable._currentIteration % 2;
1427      iterationElapsedTime = tickableCurrentTime % (iterationDuration + _loopDelay) || 0;
1428    }
1429
1430    // Checks if exactly one of _reversed and (_alternate && isOdd) is true
1431    const isReversed = _reversed ^ (_alternate && isOdd);
1432    const _ease = /** @type {Renderable} */(tickable)._ease;
1433    let iterationTime = isCurrentTimeEqualOrAboveDuration ? isReversed ? 0 : duration : isReversed ? iterationDuration - iterationElapsedTime : iterationElapsedTime;
1434    if (_ease) iterationTime = iterationDuration * _ease(iterationTime / iterationDuration) || 0;
1435    const isRunningBackwards = (parent ? parent.backwards : tickableAbsoluteTime < tickablePrevAbsoluteTime) ? !isReversed : !!isReversed;
1436
1437    tickable._currentTime = tickableAbsoluteTime;
1438    tickable._iterationTime = iterationTime;
1439    tickable.backwards = isRunningBackwards;
1440
1441    if (isCurrentTimeAboveZero && !tickable.began) {
1442      tickable.began = true;
1443      if (!muteCallbacks && !(parent && (isRunningBackwards || !parent.began))) {
1444        tickable.onBegin(/** @type {CallbackArgument} */(tickable));
1445      }
1446    } else if (tickableAbsoluteTime <= 0) {
1447      tickable.began = false;
1448    }
1449
1450    // Only triggers onLoop for tickable without children, otherwise call the the onLoop callback in the tick function
1451    // Make sure to trigger the onLoop before rendering to allow .refresh() to pickup the current values
1452    if (!muteCallbacks && !_hasChildren && isCurrentTimeAboveZero && tickable._currentIteration !== _currentIteration) {
1453      tickable.onLoop(/** @type {CallbackArgument} */(tickable));
1454    }
1455
1456    if (
1457      forcedTick ||
1458      tickMode === tickModes.AUTO && (
1459        time >= tickableDelay && time <= tickableEndTime || // Normal render
1460        time <= tickableDelay && tickablePrevTime > tickableDelay || // Playhead is before the animation start time so make sure the animation is at its initial state
1461        time >= tickableEndTime && tickablePrevTime !== duration // Playhead is after the animation end time so make sure the animation is at its end state
1462      ) ||
1463      iterationTime >= tickableEndTime && tickablePrevTime !== duration ||
1464      iterationTime <= tickableDelay && tickablePrevTime > 0 ||
1465      time <= tickablePrevTime && tickablePrevTime === duration && completed || // Force a render if a seek occurs on an completed animation
1466      isCurrentTimeEqualOrAboveDuration && !completed && isSetter // This prevents 0 duration tickables to be skipped
1467    ) {
1468
1469      if (isCurrentTimeAboveZero) {
1470        // Trigger onUpdate callback before rendering
1471        tickable.computeDeltaTime(tickablePrevTime);
1472        if (!muteCallbacks) tickable.onBeforeUpdate(/** @type {CallbackArgument} */(tickable));
1473      }
1474
1475      // Start tweens rendering
1476      if (!_hasChildren) {
1477
1478        // Time has jumped more than globals.tickThreshold so consider this tick manual
1479        const forcedRender = forcedTick || (isRunningBackwards ? deltaTime * -1 : deltaTime) >= globals.tickThreshold;
1480        const absoluteTime = tickable._offset + (parent ? parent._offset : 0) + tickableDelay + iterationTime;
1481
1482        // Only Animation can have tweens, Timer returns undefined
1483        let tween = /** @type {Tween} */(/** @type {JSAnimation} */(tickable)._head);
1484        let tweenTarget;
1485        let tweenStyle;
1486        let tweenTargetTransforms;
1487        let tweenTargetTransformsProperties;
1488        let tweenTransformsNeedUpdate = 0;
1489
1490        while (tween) {
1491
1492          const tweenComposition = tween._composition;
1493          const tweenCurrentTime = tween._currentTime;
1494          const tweenChangeDuration = tween._changeDuration;
1495          const tweenAbsEndTime = tween._absoluteStartTime + tween._changeDuration;
1496          const tweenNextRep = tween._nextRep;
1497          const tweenPrevRep = tween._prevRep;
1498          const tweenHasComposition = tweenComposition !== compositionTypes.none;
1499
1500          if ((forcedRender || (
1501              (tweenCurrentTime !== tweenChangeDuration || absoluteTime <= tweenAbsEndTime + (tweenNextRep ? tweenNextRep._delay : 0)) &&
1502              (tweenCurrentTime !== 0 || absoluteTime >= tween._absoluteStartTime)
1503            )) && (!tweenHasComposition || (
1504              !tween._isOverridden &&
1505              (!tween._isOverlapped || absoluteTime <= tweenAbsEndTime) &&
1506              (!tweenNextRep || (tweenNextRep._isOverridden || absoluteTime <= tweenNextRep._absoluteStartTime)) &&
1507              (!tweenPrevRep || (tweenPrevRep._isOverridden || (absoluteTime >= (tweenPrevRep._absoluteStartTime + tweenPrevRep._changeDuration) + tween._delay)))
1508            ))
1509          ) {
1510
1511            const tweenNewTime = tween._currentTime = clamp$1(iterationTime - tween._startTime, 0, tweenChangeDuration);
1512            const tweenProgress = tween._ease(tweenNewTime / tween._updateDuration);
1513            const tweenModifier = tween._modifier;
1514            const tweenValueType = tween._valueType;
1515            const tweenType = tween._tweenType;
1516            const tweenIsObject = tweenType === tweenTypes.OBJECT;
1517            const tweenIsNumber = tweenValueType === valueTypes.NUMBER;
1518            // Only round the in-between frames values if the final value is a string
1519            const tweenPrecision = (tweenIsNumber && tweenIsObject) || tweenProgress === 0 || tweenProgress === 1 ? -1 : globals.precision;
1520
1521            // Recompose tween value
1522            /** @type {String|Number} */
1523            let value;
1524            /** @type {Number} */
1525            let number;
1526
1527            if (tweenIsNumber) {
1528              value = number = /** @type {Number} */(tweenModifier(round$1(lerp$1(tween._fromNumber, tween._toNumber,  tweenProgress), tweenPrecision )));
1529            } else if (tweenValueType === valueTypes.UNIT) {
1530              // Rounding the values speed up string composition
1531              number = /** @type {Number} */(tweenModifier(round$1(lerp$1(tween._fromNumber, tween._toNumber,  tweenProgress), tweenPrecision)));
1532              value = `${number}${tween._unit}`;
1533            } else if (tweenValueType === valueTypes.COLOR) {
1534              const fn = tween._fromNumbers;
1535              const tn = tween._toNumbers;
1536              const r = round$1(clamp$1(/** @type {Number} */(tweenModifier(lerp$1(fn[0], tn[0], tweenProgress))), 0, 255), 0);
1537              const g = round$1(clamp$1(/** @type {Number} */(tweenModifier(lerp$1(fn[1], tn[1], tweenProgress))), 0, 255), 0);
1538              const b = round$1(clamp$1(/** @type {Number} */(tweenModifier(lerp$1(fn[2], tn[2], tweenProgress))), 0, 255), 0);
1539              const a = clamp$1(/** @type {Number} */(tweenModifier(round$1(lerp$1(fn[3], tn[3], tweenProgress), tweenPrecision))), 0, 1);
1540              value = `rgba(${r},${g},${b},${a})`;
1541              if (tweenHasComposition) {
1542                const ns = tween._numbers;
1543                ns[0] = r;
1544                ns[1] = g;
1545                ns[2] = b;
1546                ns[3] = a;
1547              }
1548            } else if (tweenValueType === valueTypes.COMPLEX) {
1549              value = tween._strings[0];
1550              for (let j = 0, l = tween._toNumbers.length; j < l; j++) {
1551                const n = /** @type {Number} */(tweenModifier(round$1(lerp$1(tween._fromNumbers[j], tween._toNumbers[j], tweenProgress), tweenPrecision)));
1552                const s = tween._strings[j + 1];
1553                value += `${s ? n + s : n}`;
1554                if (tweenHasComposition) {
1555                  tween._numbers[j] = n;
1556                }
1557              }
1558            }
1559
1560            // For additive tweens and Animatables
1561            if (tweenHasComposition) {
1562              tween._number = number;
1563            }
1564
1565            if (!internalRender && tweenComposition !== compositionTypes.blend) {
1566
1567              const tweenProperty = tween.property;
1568              tweenTarget = tween.target;
1569
1570              if (tweenIsObject) {
1571                tweenTarget[tweenProperty] = value;
1572              } else if (tweenType === tweenTypes.ATTRIBUTE) {
1573                /** @type {DOMTarget} */(tweenTarget).setAttribute(tweenProperty, /** @type {String} */(value));
1574              } else {
1575                tweenStyle = /** @type {DOMTarget} */(tweenTarget).style;
1576                if (tweenType === tweenTypes.TRANSFORM) {
1577                  if (tweenTarget !== tweenTargetTransforms) {
1578                    tweenTargetTransforms = tweenTarget;
1579                    // NOTE: Referencing the cachedTransforms in the tween property directly can be a little bit faster but appears to increase memory usage.
1580                    tweenTargetTransformsProperties = tweenTarget[transformsSymbol];
1581                  }
1582                  tweenTargetTransformsProperties[tweenProperty] = value;
1583                  tweenTransformsNeedUpdate = 1;
1584                } else if (tweenType === tweenTypes.CSS) {
1585                  tweenStyle[tweenProperty] = value;
1586                } else if (tweenType === tweenTypes.CSS_VAR) {
1587                  tweenStyle.setProperty(tweenProperty,/** @type {String} */(value));
1588                }
1589              }
1590
1591              if (isCurrentTimeAboveZero) hasRendered = 1;
1592
1593            } else {
1594              // Used for composing timeline tweens without having to do a real render
1595              tween._value = value;
1596            }
1597
1598          }
1599
1600          // NOTE: Possible improvement: Use translate(x,y) / translate3d(x,y,z) syntax
1601          // to reduce memory usage on string composition
1602          if (tweenTransformsNeedUpdate && tween._renderTransforms) {
1603            let str = emptyString;
1604            for (let key in tweenTargetTransformsProperties) {
1605              str += `${transformsFragmentStrings[key]}${tweenTargetTransformsProperties[key]}) `;
1606            }
1607            tweenStyle.transform = str;
1608            tweenTransformsNeedUpdate = 0;
1609          }
1610
1611          tween = tween._next;
1612        }
1613
1614        if (!muteCallbacks && hasRendered) {
1615          /** @type {JSAnimation} */(tickable).onRender(/** @type {JSAnimation} */(tickable));
1616        }
1617      }
1618
1619      if (!muteCallbacks && isCurrentTimeAboveZero) {
1620        tickable.onUpdate(/** @type {CallbackArgument} */(tickable));
1621      }
1622
1623    }
1624
1625    // End tweens rendering
1626
1627    // Handle setters on timeline differently and allow re-trigering the onComplete callback when seeking backwards
1628    if (parent && isSetter) {
1629      if (!muteCallbacks && (
1630        // (tickableAbsoluteTime > 0 instead) of (tickableAbsoluteTime >= duration) to prevent floating point precision issues
1631        // see: https://github.com/juliangarnier/anime/issues/1088
1632        (parent.began && !isRunningBackwards && tickableAbsoluteTime > 0 && !completed) ||
1633        (isRunningBackwards && tickableAbsoluteTime <= minValue && completed)
1634      )) {
1635        tickable.onComplete(/** @type {CallbackArgument} */(tickable));
1636        tickable.completed = !isRunningBackwards;
1637      }
1638    // If currentTime is both above 0 and at least equals to duration, handles normal onComplete or infinite loops
1639    } else if (isCurrentTimeAboveZero && isCurrentTimeEqualOrAboveDuration) {
1640      if (iterationCount === Infinity) {
1641        // Offset the tickable _startTime with its duration to reset _currentTime to 0 and continue the infinite timer
1642        tickable._startTime += tickable.duration;
1643      } else if (tickable._currentIteration >= iterationCount - 1) {
1644        // By setting paused to true, we tell the engine loop to not render this tickable and removes it from the list on the next tick
1645        tickable.paused = true;
1646        if (!completed && !_hasChildren) {
1647          // If the tickable has children, triggers onComplete() only when all children have completed in the tick function
1648          tickable.completed = true;
1649          if (!muteCallbacks && !(parent && (isRunningBackwards || !parent.began))) {
1650            tickable.onComplete(/** @type {CallbackArgument} */(tickable));
1651            tickable._resolve(/** @type {CallbackArgument} */(tickable));
1652          }
1653        }
1654      }
1655    // Otherwise set the completed flag to false
1656    } else {
1657      tickable.completed = false;
1658    }
1659
1660    // NOTE: hasRendered * direction (negative for backwards) this way we can remove the tickable.backwards property completly ?
1661    return hasRendered;
1662  };
1663
1664  /**
1665   * @param  {Tickable} tickable
1666   * @param  {Number} time
1667   * @param  {Number} muteCallbacks
1668   * @param  {Number} internalRender
1669   * @param  {Number} tickMode
1670   * @return {void}
1671   */
1672  const tick = (tickable, time, muteCallbacks, internalRender, tickMode) => {
1673    const _currentIteration = tickable._currentIteration;
1674    render(tickable, time, muteCallbacks, internalRender, tickMode);
1675    if (tickable._hasChildren) {
1676      const tl = /** @type {Timeline} */(tickable);
1677      const tlIsRunningBackwards = tl.backwards;
1678      const tlChildrenTime = internalRender ? time : tl._iterationTime;
1679      const tlCildrenTickTime = now();
1680
1681      let tlChildrenHasRendered = 0;
1682      let tlChildrenHaveCompleted = true;
1683
1684      // If the timeline has looped forward, we need to manually triggers children skipped callbacks
1685      if (!internalRender && tl._currentIteration !== _currentIteration) {
1686        const tlIterationDuration = tl.iterationDuration;
1687        forEachChildren(tl, (/** @type {JSAnimation} */child) => {
1688          if (!tlIsRunningBackwards) {
1689            // Force an internal render to trigger the callbacks if the child has not completed on loop
1690            if (!child.completed && !child.backwards && child._currentTime < child.iterationDuration) {
1691              render(child, tlIterationDuration, muteCallbacks, 1, tickModes.FORCE);
1692            }
1693            // Reset their began and completed flags to allow retrigering callbacks on the next iteration
1694            child.began = false;
1695            child.completed = false;
1696          } else {
1697            const childDuration = child.duration;
1698            const childStartTime = child._offset + child._delay;
1699            const childEndTime = childStartTime + childDuration;
1700            // Triggers the onComplete callback on reverse for children on the edges of the timeline
1701            if (!muteCallbacks && childDuration <= minValue && (!childStartTime || childEndTime === tlIterationDuration)) {
1702              child.onComplete(child);
1703            }
1704          }
1705        });
1706        if (!muteCallbacks) tl.onLoop(/** @type {CallbackArgument} */(tl));
1707      }
1708
1709      forEachChildren(tl, (/** @type {JSAnimation} */child) => {
1710        const childTime = round$1((tlChildrenTime - child._offset) * child._speed, 12); // Rounding is needed when using seconds
1711        const childTickMode = child._fps < tl._fps ? child.requestTick(tlCildrenTickTime) : tickMode;
1712        tlChildrenHasRendered += render(child, childTime, muteCallbacks, internalRender, childTickMode);
1713        if (!child.completed && tlChildrenHaveCompleted) tlChildrenHaveCompleted = false;
1714      }, tlIsRunningBackwards);
1715
1716      // Renders on timeline are triggered by its children so it needs to be set after rendering the children
1717      if (!muteCallbacks && tlChildrenHasRendered) tl.onRender(/** @type {CallbackArgument} */(tl));
1718
1719      // Triggers the timeline onComplete() once all chindren all completed and the current time has reached the end
1720      if ((tlChildrenHaveCompleted || tlIsRunningBackwards) && tl._currentTime >= tl.duration) {
1721        // Make sure the paused flag is false in case it has been skipped in the render function
1722        tl.paused = true;
1723        if (!tl.completed) {
1724          tl.completed = true;
1725          if (!muteCallbacks) {
1726            tl.onComplete(/** @type {CallbackArgument} */(tl));
1727            tl._resolve(/** @type {CallbackArgument} */(tl));
1728          }
1729        }
1730      }
1731    }
1732  };
1733
1734  
1735
1736  
1737
1738  const propertyNamesCache = {};
1739
1740  /**
1741   * @param  {String} propertyName
1742   * @param  {Target} target
1743   * @param  {tweenTypes} tweenType
1744   * @return {String}
1745   */
1746  const sanitizePropertyName = (propertyName, target, tweenType) => {
1747    if (tweenType === tweenTypes.TRANSFORM) {
1748      const t = shortTransforms.get(propertyName);
1749      return t ? t : propertyName;
1750    } else if (
1751      tweenType === tweenTypes.CSS ||
1752      // Handle special cases where properties like "strokeDashoffset" needs to be set as "stroke-dashoffset"
1753      // but properties like "baseFrequency" should stay in lowerCamelCase
1754      (tweenType === tweenTypes.ATTRIBUTE && (isSvg(target) && propertyName in /** @type {DOMTarget} */(target).style))
1755    ) {
1756      const cachedPropertyName = propertyNamesCache[propertyName];
1757      if (cachedPropertyName) {
1758        return cachedPropertyName;
1759      } else {
1760        const lowerCaseName = propertyName ? toLowerCase(propertyName) : propertyName;
1761        propertyNamesCache[propertyName] = lowerCaseName;
1762        return lowerCaseName;
1763      }
1764    } else {
1765      return propertyName;
1766    }
1767  };
1768
1769  /**
1770   * @template {Renderable} T
1771   * @param {T} renderable
1772   * @return {T}
1773   */
1774  const cleanInlineStyles = renderable => {
1775    // Allow cleanInlineStyles() to be called on timelines
1776    if (renderable._hasChildren) {
1777      forEachChildren(renderable, cleanInlineStyles, true);
1778    } else {
1779      const animation = /** @type {JSAnimation} */(renderable);
1780      animation.pause();
1781      forEachChildren(animation, (/** @type {Tween} */tween) => {
1782        const tweenProperty = tween.property;
1783        const tweenTarget = tween.target;
1784        if (tweenTarget[isDomSymbol]) {
1785          const targetStyle = /** @type {DOMTarget} */(tweenTarget).style;
1786          const originalInlinedValue = tween._inlineValue;
1787          const tweenHadNoInlineValue = isNil(originalInlinedValue) || originalInlinedValue === emptyString;
1788          if (tween._tweenType === tweenTypes.TRANSFORM) {
1789            const cachedTransforms = tweenTarget[transformsSymbol];
1790            if (tweenHadNoInlineValue) {
1791              delete cachedTransforms[tweenProperty];
1792            } else {
1793              cachedTransforms[tweenProperty] = originalInlinedValue;
1794            }
1795            if (tween._renderTransforms) {
1796              if (!Object.keys(cachedTransforms).length) {
1797                targetStyle.removeProperty('transform');
1798              } else {
1799                let str = emptyString;
1800                for (let key in cachedTransforms) {
1801                  str += transformsFragmentStrings[key] + cachedTransforms[key] + ') ';
1802                }
1803                targetStyle.transform = str;
1804              }
1805            }
1806          } else {
1807            if (tweenHadNoInlineValue) {
1808              targetStyle.removeProperty(toLowerCase(tweenProperty));
1809            } else {
1810              targetStyle[tweenProperty] = originalInlinedValue;
1811            }
1812          }
1813          if (animation._tail === tween) {
1814            animation.targets.forEach(t => {
1815              if (t.getAttribute && t.getAttribute('style') === emptyString) {
1816                t.removeAttribute('style');
1817              }          });
1818          }
1819        }
1820      });
1821    }
1822    return renderable;
1823  };
1824
1825  
1826
1827  /*
1828   * Base class to control framerate and playback rate.
1829   * Inherited by Engine, Timer, Animation and Timeline.
1830   */
1831  class Clock {
1832
1833    /** @param {Number} [initTime] */
1834    constructor(initTime = 0) {
1835      /** @type {Number} */
1836      this.deltaTime = 0;
1837      /** @type {Number} */
1838      this._currentTime = initTime;
1839      /** @type {Number} */
1840      this._lastTickTime = initTime;
1841      /** @type {Number} */
1842      this._startTime = initTime;
1843      /** @type {Number} */
1844      this._lastTime = initTime;
1845      /** @type {Number} */
1846      this._scheduledTime = 0;
1847      /** @type {Number} */
1848      this._frameDuration = K / maxFps;
1849      /** @type {Number} */
1850      this._fps = maxFps;
1851      /** @type {Number} */
1852      this._speed = 1;
1853      /** @type {Boolean} */
1854      this._hasChildren = false;
1855      /** @type {Tickable|Tween} */
1856      this._head = null;
1857      /** @type {Tickable|Tween} */
1858      this._tail = null;
1859    }
1860
1861    get fps() {
1862      return this._fps;
1863    }
1864
1865    set fps(frameRate) {
1866      const previousFrameDuration = this._frameDuration;
1867      const fr = +frameRate;
1868      const fps = fr < minValue ? minValue : fr;
1869      const frameDuration = K / fps;
1870      if (fps > defaults.frameRate) defaults.frameRate = fps;
1871      this._fps = fps;
1872      this._frameDuration = frameDuration;
1873      this._scheduledTime += frameDuration - previousFrameDuration;
1874    }
1875
1876    get speed() {
1877      return this._speed;
1878    }
1879
1880    set speed(playbackRate) {
1881      const pbr = +playbackRate;
1882      this._speed = pbr < minValue ? minValue : pbr;
1883    }
1884
1885    /**
1886     * @param  {Number} time
1887     * @return {tickModes}
1888     */
1889    requestTick(time) {
1890      const scheduledTime = this._scheduledTime;
1891      this._lastTickTime = time;
1892      // If the current time is lower than the scheduled time
1893      // this means not enough time has passed to hit one frameDuration
1894      // so skip that frame
1895      if (time < scheduledTime) return tickModes.NONE;
1896      const frameDuration = this._frameDuration;
1897      const frameDelta = time - scheduledTime;
1898      // Ensures that _scheduledTime progresses in steps of at least 1 frameDuration.
1899      // Skips ahead if the actual elapsed time is higher.
1900      this._scheduledTime += frameDelta < frameDuration ? frameDuration : frameDelta;
1901      return tickModes.AUTO;
1902    }
1903
1904    /**
1905     * @param  {Number} time
1906     * @return {Number}
1907     */
1908    computeDeltaTime(time) {
1909      const delta = time - this._lastTime;
1910      this.deltaTime = delta;
1911      this._lastTime = time;
1912      return delta;
1913    }
1914
1915  }
1916
1917  const additive = {
1918    animation: null,
1919    update: noop,
1920  };
1921
1922  
1923
1924  /**
1925   * @typedef AdditiveAnimation
1926   * @property {Number} duration
1927   * @property {Number} _offset
1928   * @property {Number} _delay
1929   * @property {Tween} _head
1930   * @property {Tween} _tail
1931   */
1932
1933  /**
1934   * @param  {TweenAdditiveLookups} lookups
1935   * @return {AdditiveAnimation}
1936   */
1937  const addAdditiveAnimation = lookups => {
1938    let animation = additive.animation;
1939    if (!animation) {
1940      animation = {
1941        duration: minValue,
1942        computeDeltaTime: noop,
1943        _offset: 0,
1944        _delay: 0,
1945        _head: null,
1946        _tail: null,
1947      };
1948      additive.animation = animation;
1949      additive.update = () => {
1950        lookups.forEach(propertyAnimation => {
1951          for (let propertyName in propertyAnimation) {
1952            const tweens = propertyAnimation[propertyName];
1953            const lookupTween = tweens._head;
1954            if (lookupTween) {
1955              const valueType = lookupTween._valueType;
1956              const additiveValues = valueType === valueTypes.COMPLEX || valueType === valueTypes.COLOR ? cloneArray(lookupTween._fromNumbers) : null;
1957              let additiveValue = lookupTween._fromNumber;
1958              let tween = tweens._tail;
1959              while (tween && tween !== lookupTween) {
1960                if (additiveValues) {
1961                  for (let i = 0, l = tween._numbers.length; i < l; i++) additiveValues[i] += tween._numbers[i];
1962                } else {
1963                  additiveValue += tween._number;
1964                }
1965                tween = tween._prevAdd;
1966              }
1967              lookupTween._toNumber = additiveValue;
1968              lookupTween._toNumbers = additiveValues;
1969            }
1970          }
1971        });
1972        // TODO: Avoid polymorphism here, idealy the additive animation should be a regular animation with a higher priority in the render loop
1973        render(animation, 1, 1, 0, tickModes.FORCE);
1974      };
1975    }
1976    return animation;
1977  };
1978
1979  
1980
1981  
1982
1983  const engineTickMethod = /*#__PURE__*/ (() => isBrowser ? requestAnimationFrame : setImmediate)();
1984  const engineCancelMethod = /*#__PURE__*/ (() => isBrowser ? cancelAnimationFrame : clearImmediate)();
1985
1986  class Engine extends Clock {
1987
1988    /** @param {Number} [initTime] */
1989    constructor(initTime) {
1990      super(initTime);
1991      this.useDefaultMainLoop = true;
1992      this.pauseOnDocumentHidden = true;
1993      /** @type {DefaultsParams} */
1994      this.defaults = defaults;
1995      // this.paused = isBrowser && doc.hidden ? true  : false;
vendor: 4,098 bytes, lines 1996-2143
1996      this.paused = true;
1997      /** @type {Number|NodeJS.Immediate} */
1998      this.reqId = 0;
1999    }
2000
2001    update() {
2002      const time = this._currentTime = now();
2003      if (this.requestTick(time)) {
2004        this.computeDeltaTime(time);
2005        const engineSpeed = this._speed;
2006        const engineFps = this._fps;
2007        let activeTickable = /** @type {Tickable} */(this._head);
2008        while (activeTickable) {
2009          const nextTickable = activeTickable._next;
2010          if (!activeTickable.paused) {
2011            tick(
2012              activeTickable,
2013              (time - activeTickable._startTime) * activeTickable._speed * engineSpeed,
2014              0, // !muteCallbacks
2015              0, // !internalRender
2016              activeTickable._fps < engineFps ? activeTickable.requestTick(time) : tickModes.AUTO
2017            );
2018          } else {
2019            removeChild(this, activeTickable);
2020            this._hasChildren = !!this._tail;
2021            activeTickable._running = false;
2022            if (activeTickable.completed && !activeTickable._cancelled) {
2023              activeTickable.cancel();
2024            }
2025          }
2026          activeTickable = nextTickable;
2027        }
2028        additive.update();
2029      }
2030    }
2031
2032    wake() {
2033      if (this.useDefaultMainLoop && !this.reqId) {
2034        // Imediatly request a tick to update engine._lastTickTime and get accurate offsetPosition calculation in timer.js
2035        this.requestTick(now());
2036        this.reqId = engineTickMethod(tickEngine);
2037      }
2038      return this;
2039    }
2040
2041    pause() {
2042      if (!this.reqId) return;
2043      this.paused = true;
2044      return killEngine();
2045    }
2046
2047    resume() {
2048      if (!this.paused) return;
2049      this.paused = false;
2050      forEachChildren(this, (/** @type {Tickable} */child) => child.resetTime());
2051      return this.wake();
2052    }
2053
2054    // Getter and setter for speed
2055    get speed() {
2056      return this._speed * (globals.timeScale === 1 ? 1 : K);
2057    }
2058
2059    set speed(playbackRate) {
2060      this._speed = playbackRate * globals.timeScale;
2061      forEachChildren(this, (/** @type {Tickable} */child) => child.speed = child._speed);
2062    }
2063
2064    // Getter and setter for timeUnit
2065    get timeUnit() {
2066      return globals.timeScale === 1 ? 'ms' : 's';
2067    }
2068
2069    set timeUnit(unit) {
2070      const secondsScale = 0.001;
2071      const isSecond = unit === 's';
2072      const newScale = isSecond ? secondsScale : 1;
2073      if (globals.timeScale !== newScale) {
2074        globals.timeScale = newScale;
2075        globals.tickThreshold = 200 * newScale;
2076        const scaleFactor = isSecond ? secondsScale : K;
2077        /** @type {Number} */
2078        (this.defaults.duration) *= scaleFactor;
2079        this._speed *= scaleFactor;
2080      }
2081    }
2082
2083    // Getter and setter for precision
2084    get precision() {
2085      return globals.precision;
2086    }
2087
2088    set precision(precision) {
2089      globals.precision = precision;
2090    }
2091
2092  }
2093
2094  const engine = /*#__PURE__*/(() => {
2095    const engine = new Engine(now());
2096    if (isBrowser) {
2097      globalVersions.engine = engine;
2098      doc.addEventListener('visibilitychange', () => {
2099        if (!engine.pauseOnDocumentHidden) return;
2100        doc.hidden ? engine.pause() : engine.resume();
2101      });
2102    }
2103    return engine;
2104  })();
2105
2106
2107  const tickEngine = () => {
2108    if (engine._head) {
2109      engine.reqId = engineTickMethod(tickEngine);
2110      engine.update();
2111    } else {
2112      engine.reqId = 0;
2113    }
2114  };
2115
2116  const killEngine = () => {
2117    engineCancelMethod(/** @type {NodeJS.Immediate & Number} */(engine.reqId));
2118    engine.reqId = 0;
2119    return engine;
2120  };
2121
2122  
2123
2124  const lookups = {
2125    /** @type {TweenReplaceLookups} */
2126    _rep: new WeakMap(),
2127    /** @type {TweenAdditiveLookups} */
2128    _add: new Map(),
2129  };
2130
2131  /**
2132   * @param  {Target} target
2133   * @param  {String} property
2134   * @param  {String} lookup
2135   * @return {TweenPropertySiblings}
2136   */
2137  const getTweenSiblings = (target, property, lookup = '_rep') => {
2138    const lookupMap = lookups[lookup];
2139    let targetLookup = lookupMap.get(target);
2140    if (!targetLookup) {
2141      targetLookup = {};
2142      lookupMap.set(target, targetLookup);
2143    }
vendor: 8,670 bytes, lines 2144-2391
2144    return targetLookup[property] ? targetLookup[property] : targetLookup[property] = {
2145      _head: null,
2146      _tail: null,
2147    }
2148  };
2149
2150  /**
2151   * @param  {Tween} p
2152   * @param  {Tween} c
2153   * @return {Number|Boolean}
2154   */
2155  const addTweenSortMethod = (p, c) => {
2156    return p._isOverridden || p._absoluteStartTime > c._absoluteStartTime;
2157  };
2158
2159  /**
2160   * @param {Tween} tween
2161   */
2162  const overrideTween = tween => {
2163    tween._isOverlapped = 1;
2164    tween._isOverridden = 1;
2165    tween._changeDuration = minValue;
2166    tween._currentTime = minValue;
2167  };
2168
2169  /**
2170   * @param  {Tween} tween
2171   * @param  {TweenPropertySiblings} siblings
2172   * @return {Tween}
2173   */
2174  const composeTween = (tween, siblings) => {
2175
2176    const tweenCompositionType = tween._composition;
2177
2178    // Handle replaced tweens
2179
2180    if (tweenCompositionType === compositionTypes.replace) {
2181
2182      const tweenAbsStartTime = tween._absoluteStartTime;
2183
2184      addChild(siblings, tween, addTweenSortMethod, '_prevRep', '_nextRep');
2185
2186      const prevSibling = tween._prevRep;
2187
2188      // Update the previous siblings for composition replace tweens
2189
2190      if (prevSibling) {
2191
2192        const prevParent = prevSibling.parent;
2193        const prevAbsEndTime = prevSibling._absoluteStartTime + prevSibling._changeDuration;
2194
2195        // Handle looped animations tween
2196
2197        if (
2198          // Check if the previous tween is from a different animation
2199          tween.parent.id !== prevParent.id &&
2200          // Check if the animation has loops
2201          prevParent.iterationCount> 1 &&
2202          // Check if _absoluteChangeEndTime of last loop overlaps the current tween
2203          prevAbsEndTime + (prevParent.duration - prevParent.iterationDuration) > tweenAbsStartTime
2204        ) {
2205
2206          // TODO: Find a way to only override the iterations overlapping with the tween
2207          overrideTween(prevSibling);
2208
2209          let prevPrevSibling = prevSibling._prevRep;
2210
2211          // If the tween was part of a set of keyframes, override its siblings
2212          while (prevPrevSibling && prevPrevSibling.parent.id === prevParent.id) {
2213            overrideTween(prevPrevSibling);
2214            prevPrevSibling = prevPrevSibling._prevRep;
2215          }
2216
2217        }
2218
2219        const absoluteUpdateStartTime = tweenAbsStartTime - tween._delay;
2220
2221        if (prevAbsEndTime > absoluteUpdateStartTime) {
2222
2223          const prevChangeStartTime = prevSibling._startTime;
2224          const prevTLOffset = prevAbsEndTime - (prevChangeStartTime + prevSibling._updateDuration);
2225          // Rounding is necessary here to minimize floating point errors when working in seconds
2226          const updatedPrevChangeDuration = round$1(absoluteUpdateStartTime - prevTLOffset - prevChangeStartTime, 12);
2227
2228          prevSibling._changeDuration = updatedPrevChangeDuration;
2229          prevSibling._currentTime = updatedPrevChangeDuration;
2230          prevSibling._isOverlapped = 1;
2231
2232          // Override the previous tween if its new _changeDuration is lower than minValue
2233          // TODO: See if it's even neceseeary to test against minValue, checking for 0 might be enough
2234          if (updatedPrevChangeDuration < minValue) {
2235            overrideTween(prevSibling);
2236          }
2237        }
2238
2239        // Pause (and cancel) the parent if it only contains overlapped tweens
2240
2241        let pausePrevParentAnimation = true;
2242
2243        forEachChildren(prevParent, (/** @type Tween */t) => {
2244          if (!t._isOverlapped) pausePrevParentAnimation = false;
2245        });
2246
2247        if (pausePrevParentAnimation) {
2248          const prevParentTL = prevParent.parent;
2249          if (prevParentTL) {
2250            let pausePrevParentTL = true;
2251            forEachChildren(prevParentTL, (/** @type JSAnimation */a) => {
2252              if (a !== prevParent) {
2253                forEachChildren(a, (/** @type Tween */t) => {
2254                  if (!t._isOverlapped) pausePrevParentTL = false;
2255                });
2256              }
2257            });
2258            if (pausePrevParentTL) {
2259              prevParentTL.cancel();
2260            }
2261          } else {
2262            prevParent.cancel();
2263            // Previously, calling .cancel() on a timeline child would affect the render order of other children
2264            // Worked around this by marking it as .completed and using .pause() for safe removal in the engine loop
2265            // This is no longer needed since timeline tween composition is now handled separately
2266            // Keeping this here for reference
2267            // prevParent.completed = true;
2268            // prevParent.pause();
2269          }
2270        }
2271
2272      }
2273
2274      // let nextSibling = tween._nextRep;
2275
2276      // // All the next siblings are automatically overridden
2277
2278      // if (nextSibling && nextSibling._absoluteStartTime >= tweenAbsStartTime) {
2279      //   while (nextSibling) {
2280      //     overrideTween(nextSibling);
2281      //     nextSibling = nextSibling._nextRep;
2282      //   }
2283      // }
2284
2285      // if (nextSibling && nextSibling._absoluteStartTime < tweenAbsStartTime) {
2286      //   while (nextSibling) {
2287      //     overrideTween(nextSibling);
2288      //     console.log(tween.id, nextSibling.id);
2289      //     nextSibling = nextSibling._nextRep;
2290      //   }
2291      // }
2292
2293    // Handle additive tweens composition
2294
2295    } else if (tweenCompositionType === compositionTypes.blend) {
2296
2297      const additiveTweenSiblings = getTweenSiblings(tween.target, tween.property, '_add');
2298      const additiveAnimation = addAdditiveAnimation(lookups._add);
2299
2300      let lookupTween = additiveTweenSiblings._head;
2301
2302      if (!lookupTween) {
2303        lookupTween = { ...tween };
2304        lookupTween._composition = compositionTypes.replace;
2305        lookupTween._updateDuration = minValue;
2306        lookupTween._startTime = 0;
2307        lookupTween._numbers = cloneArray(tween._fromNumbers);
2308        lookupTween._number = 0;
2309        lookupTween._next = null;
2310        lookupTween._prev = null;
2311        addChild(additiveTweenSiblings, lookupTween);
2312        addChild(additiveAnimation, lookupTween);
2313      }
2314
2315      // Convert the values of TO to FROM and set TO to 0
2316
2317      const toNumber = tween._toNumber;
2318      tween._fromNumber = lookupTween._fromNumber - toNumber;
2319      tween._toNumber = 0;
2320      tween._numbers = cloneArray(tween._fromNumbers);
2321      tween._number = 0;
2322      lookupTween._fromNumber = toNumber;
2323
2324      if (tween._toNumbers) {
2325        const toNumbers = cloneArray(tween._toNumbers);
2326        if (toNumbers) {
2327          toNumbers.forEach((value, i) => {
2328            tween._fromNumbers[i] = lookupTween._fromNumbers[i] - value;
2329            tween._toNumbers[i] = 0;
2330          });
2331        }
2332        lookupTween._fromNumbers = toNumbers;
2333      }
2334
2335      addChild(additiveTweenSiblings, tween, null, '_prevAdd', '_nextAdd');
2336
2337    }
2338
2339    return tween;
2340
2341  };
2342
2343  /**
2344   * @param  {Tween} tween
2345   * @return {Tween}
2346   */
2347  const removeTweenSliblings = tween => {
2348    const tweenComposition = tween._composition;
2349    if (tweenComposition !== compositionTypes.none) {
2350      const tweenTarget = tween.target;
2351      const tweenProperty = tween.property;
2352      const replaceTweensLookup = lookups._rep;
2353      const replaceTargetProps = replaceTweensLookup.get(tweenTarget);
2354      const tweenReplaceSiblings = replaceTargetProps[tweenProperty];
2355      removeChild(tweenReplaceSiblings, tween, '_prevRep', '_nextRep');
2356      if (tweenComposition === compositionTypes.blend) {
2357        const addTweensLookup = lookups._add;
2358        const addTargetProps = addTweensLookup.get(tweenTarget);
2359        if (!addTargetProps) return;
2360        const additiveTweenSiblings = addTargetProps[tweenProperty];
2361        const additiveAnimation = additive.animation;
2362        removeChild(additiveTweenSiblings, tween, '_prevAdd', '_nextAdd');
2363        // If only one tween is left in the additive lookup, it's the tween lookup
2364        const lookupTween = additiveTweenSiblings._head;
2365        if (lookupTween && lookupTween === additiveTweenSiblings._tail) {
2366          removeChild(additiveTweenSiblings, lookupTween, '_prevAdd', '_nextAdd');
2367          removeChild(additiveAnimation, lookupTween);
2368          let shouldClean = true;
2369          for (let prop in addTargetProps) {
2370            if (addTargetProps[prop]._head) {
2371              shouldClean = false;
2372              break;
2373            }
2374          }
2375          if (shouldClean) {
2376            addTweensLookup.delete(tweenTarget);
2377          }
2378        }
2379      }
2380    }
2381    return tween;
2382  };
2383
2384  /**
2385   * @param  {TargetsArray} targetsArray
2386   * @param  {JSAnimation} animation
2387   * @param  {String} [propertyName]
2388   * @return {Boolean}
2389   */
2390  const removeTargetsFromJSAnimation = (targetsArray, animation, propertyName) => {
2391    let tweensMatchesTargets = false;
vendor: 39,435 bytes, lines 2392-3510
2392    forEachChildren(animation, (/**@type {Tween} */tween) => {
2393      const tweenTarget = tween.target;
2394      if (targetsArray.includes(tweenTarget)) {
2395        const tweenName = tween.property;
2396        const tweenType = tween._tweenType;
2397        const normalizePropName = sanitizePropertyName(propertyName, tweenTarget, tweenType);
2398        if (!normalizePropName || normalizePropName && normalizePropName === tweenName) {
2399          // Make sure to flag the previous CSS transform tween to renderTransform
2400          if (tween.parent._tail === tween &&
2401              tween._tweenType === tweenTypes.TRANSFORM &&
2402              tween._prev &&
2403              tween._prev._tweenType === tweenTypes.TRANSFORM
2404          ) {
2405            tween._prev._renderTransforms = 1;
2406          }
2407          // Removes the tween from the selected animation
2408          removeChild(animation, tween);
2409          // Detach the tween from its siblings to make sure blended tweens are correctlly removed
2410          removeTweenSliblings(tween);
2411          tweensMatchesTargets = true;
2412        }
2413      }
2414    }, true);
2415    return tweensMatchesTargets;
2416  };
2417
2418  /**
2419   * @param  {TargetsArray} targetsArray
2420   * @param  {Renderable} [renderable]
2421   * @param  {String} [propertyName]
2422   */
2423  const removeTargetsFromRenderable = (targetsArray, renderable, propertyName) => {
2424    const parent = /** @type {Renderable|typeof engine} **/(renderable ? renderable : engine);
2425    let removeMatches;
2426    if (parent._hasChildren) {
2427      let iterationDuration = 0;
2428      forEachChildren(parent, (/** @type {Renderable} */child) => {
2429        if (!child._hasChildren) {
2430          removeMatches = removeTargetsFromJSAnimation(targetsArray, /** @type {JSAnimation} */(child), propertyName);
2431          // Remove the child from its parent if no tweens and no children left after the removal
2432          if (removeMatches && !child._head) {
2433            child.cancel();
2434            removeChild(parent, child);
2435          } else {
2436            // Calculate the new iterationDuration value to handle onComplete with last child in render()
2437            const childTLOffset = child._offset + child._delay;
2438            const childDur = childTLOffset + child.duration;
2439            if (childDur > iterationDuration) {
2440              iterationDuration = childDur;
2441            }
2442          }
2443        }
2444        // Make sure to also remove engine's children targets
2445        // NOTE: Avoid recursion?
2446        if (child._head) {
2447          removeTargetsFromRenderable(targetsArray, child, propertyName);
2448        } else {
2449          child._hasChildren = false;
2450        }
2451      }, true);
2452      // Update iterationDuration value to handle onComplete with last child in render()
2453      if (!isUnd(/** @type {Renderable} */(parent).iterationDuration)) {
2454        /** @type {Renderable} */(parent).iterationDuration = iterationDuration;
2455      }
2456    } else {
2457      removeMatches = removeTargetsFromJSAnimation(
2458        targetsArray,
2459        /** @type {JSAnimation} */(parent),
2460        propertyName
2461      );
2462    }
2463    if (removeMatches && !parent._head) {
2464      parent._hasChildren = false;
2465      // Cancel the parent if there are no tweens and no children left after the removal
2466      // We have to check if the .cancel() method exist to handle cases where the parent is the engine itself
2467      if (/** @type {Renderable} */(parent).cancel) /** @type {Renderable} */(parent).cancel();
2468    }
2469  };
2470
2471  
2472
2473  
2474
2475  
2476
2477  /**
2478   * @param  {Timer} timer
2479   * @return {Timer}
2480   */
2481  const resetTimerProperties = timer => {
2482    timer.paused = true;
2483    timer.began = false;
2484    timer.completed = false;
2485    return timer;
2486  };
2487
2488  /**
2489   * @param  {Timer} timer
2490   * @return {Timer}
2491   */
2492  const reviveTimer = timer => {
2493    if (!timer._cancelled) return timer;
2494    if (timer._hasChildren) {
2495      forEachChildren(timer, reviveTimer);
2496    } else {
2497      forEachChildren(timer, (/** @type {Tween} tween */tween) => {
2498        if (tween._composition !== compositionTypes.none) {
2499          composeTween(tween, getTweenSiblings(tween.target, tween.property));
2500        }
2501      });
2502    }
2503    timer._cancelled = 0;
2504    return timer;
2505  };
2506
2507  let timerId = 0;
2508
2509  /**
2510   * Base class used to create Timers, Animations and Timelines
2511   */
2512  class Timer extends Clock {
2513    /**
2514     * @param {TimerParams} [parameters]
2515     * @param {Timeline} [parent]
2516     * @param {Number} [parentPosition]
2517     */
2518    constructor(parameters = {}, parent = null, parentPosition = 0) {
2519
2520      super(0);
2521
2522      ++timerId;
2523
2524      const {
2525        id,
2526        delay,
2527        duration,
2528        reversed,
2529        alternate,
2530        loop,
2531        loopDelay,
2532        autoplay,
2533        frameRate,
2534        playbackRate,
2535        onComplete,
2536        onLoop,
2537        onPause,
2538        onBegin,
2539        onBeforeUpdate,
2540        onUpdate,
2541      } = parameters;
2542
2543      if (scope.current) scope.current.register(this);
2544
2545      const timerInitTime = parent ? 0 : engine._lastTickTime;
2546      const timerDefaults = parent ? parent.defaults : globals.defaults;
2547      const timerDelay = /** @type {Number} */(isFnc(delay) || isUnd(delay) ? timerDefaults.delay : +delay);
2548      const timerDuration = isFnc(duration) || isUnd(duration) ? Infinity : +duration;
2549      const timerLoop = setValue(loop, timerDefaults.loop);
2550      const timerLoopDelay = setValue(loopDelay, timerDefaults.loopDelay);
2551      let timerIterationCount = timerLoop === true ||
2552                                timerLoop === Infinity ||
2553                                /** @type {Number} */(timerLoop) < 0 ? Infinity :
2554                                /** @type {Number} */(timerLoop) + 1;
2555
2556      if (devTools) {
2557        const isInfinite = timerIterationCount === Infinity;
2558        const registered = devTools.register(this, parameters, isInfinite);
2559        if (registered && isInfinite) {
2560          const minIterations = alternate ? 2 : 1;
2561          const iterations = parent ? devTools.maxNestedInfiniteLoops : devTools.maxInfiniteLoops;
2562          timerIterationCount = Math.max(iterations, minIterations);
2563        }
2564      }
2565
2566      let offsetPosition = 0;
2567
2568      if (parent) {
2569        offsetPosition = parentPosition;
2570      } else {
2571        // Make sure to tick the engine once if not currently running to get up to date engine._lastTickTime
2572        // to avoid big gaps with the following offsetPosition calculation
2573        if (!engine.reqId) engine.requestTick(now());
2574        // Make sure to scale the offset position with globals.timeScale to properly handle seconds unit
2575        offsetPosition = (engine._lastTickTime - engine._startTime) * globals.timeScale;
2576      }
2577
2578      // Timer's parameters
2579      /** @type {String|Number} */
2580      this.id = !isUnd(id) ? id : timerId;
2581      /** @type {Timeline} */
2582      this.parent = parent;
2583      // Total duration of the timer
2584      this.duration = clampInfinity(((timerDuration + timerLoopDelay) * timerIterationCount) - timerLoopDelay) || minValue;
2585      /** @type {Boolean} */
2586      this.backwards = false;
2587      /** @type {Boolean} */
2588      this.paused = true;
2589      /** @type {Boolean} */
2590      this.began = false;
2591      /** @type {Boolean} */
2592      this.completed = false;
2593      /** @type {Callback<this>} */
2594      this.onBegin = onBegin || timerDefaults.onBegin;
2595      /** @type {Callback<this>} */
2596      this.onBeforeUpdate = onBeforeUpdate || timerDefaults.onBeforeUpdate;
2597      /** @type {Callback<this>} */
2598      this.onUpdate = onUpdate || timerDefaults.onUpdate;
2599      /** @type {Callback<this>} */
2600      this.onLoop = onLoop || timerDefaults.onLoop;
2601      /** @type {Callback<this>} */
2602      this.onPause = onPause || timerDefaults.onPause;
2603      /** @type {Callback<this>} */
2604      this.onComplete = onComplete || timerDefaults.onComplete;
2605      /** @type {Number} */
2606      this.iterationDuration = timerDuration; // Duration of one loop
2607      /** @type {Number} */
2608      this.iterationCount = timerIterationCount; // Number of loops
2609      /** @type {Boolean|ScrollObserver} */
2610      this._autoplay = parent ? false : setValue(autoplay, timerDefaults.autoplay);
2611      /** @type {Number} */
2612      this._offset = offsetPosition;
2613      /** @type {Number} */
2614      this._delay = timerDelay;
2615      /** @type {Number} */
2616      this._loopDelay = timerLoopDelay;
2617      /** @type {Number} */
2618      this._iterationTime = 0;
2619      /** @type {Number} */
2620      this._currentIteration = 0; // Current loop index
2621      /** @type {Function} */
2622      this._resolve = noop; // Used by .then()
2623      /** @type {Boolean} */
2624      this._running = false;
2625      /** @type {Number} */
2626      this._reversed = +setValue(reversed, timerDefaults.reversed);
2627      /** @type {Number} */
2628      this._reverse = this._reversed;
2629      /** @type {Number} */
2630      this._cancelled = 0;
2631      /** @type {Boolean} */
2632      this._alternate = setValue(alternate, timerDefaults.alternate);
2633      /** @type {Renderable} */
2634      this._prev = null;
2635      /** @type {Renderable} */
2636      this._next = null;
2637
2638      // Clock's parameters
2639      /** @type {Number} */
2640      this._lastTickTime = timerInitTime;
2641      /** @type {Number} */
2642      this._startTime = timerInitTime;
2643      /** @type {Number} */
2644      this._lastTime = timerInitTime;
2645      /** @type {Number} */
2646      this._fps = setValue(frameRate, timerDefaults.frameRate);
2647      /** @type {Number} */
2648      this._speed = setValue(playbackRate, timerDefaults.playbackRate);
2649    }
2650
2651    get cancelled() {
2652      return !!this._cancelled;
2653    }
2654
2655    set cancelled(cancelled) {
2656      cancelled ? this.cancel() : this.reset(true).play();
2657    }
2658
2659    get currentTime() {
2660      return clamp$1(round$1(this._currentTime, globals.precision), -this._delay, this.duration);
2661    }
2662
2663    set currentTime(time) {
2664      const paused = this.paused;
2665      // Pausing the timer is necessary to avoid time jumps on a running instance
2666      this.pause().seek(+time);
2667      if (!paused) this.resume();
2668    }
2669
2670    get iterationCurrentTime() {
2671      return clamp$1(round$1(this._iterationTime, globals.precision), 0, this.iterationDuration);
2672    }
2673
2674    set iterationCurrentTime(time) {
2675      this.currentTime = (this.iterationDuration * this._currentIteration) + time;
2676    }
2677
2678    get progress() {
2679      return clamp$1(round$1(this._currentTime / this.duration, 10), 0, 1);
2680    }
2681
2682    set progress(progress) {
2683      this.currentTime = this.duration * progress;
2684    }
2685
2686    get iterationProgress() {
2687      return clamp$1(round$1(this._iterationTime / this.iterationDuration, 10), 0, 1);
2688    }
2689
2690    set iterationProgress(progress) {
2691      const iterationDuration = this.iterationDuration;
2692      this.currentTime = (iterationDuration * this._currentIteration) + (iterationDuration * progress);
2693    }
2694
2695    get currentIteration() {
2696      return this._currentIteration;
2697    }
2698
2699    set currentIteration(iterationCount) {
2700      this.currentTime = (this.iterationDuration * clamp$1(+iterationCount, 0, this.iterationCount - 1));
2701    }
2702
2703    get reversed() {
2704      return !!this._reversed;
2705    }
2706
2707    set reversed(reverse) {
2708      reverse ? this.reverse() : this.play();
2709    }
2710
2711    get speed() {
2712      return super.speed;
2713    }
2714
2715    set speed(playbackRate) {
2716      super.speed = playbackRate;
2717      this.resetTime();
2718    }
2719
2720    /**
2721     * @param  {Boolean} [softReset]
2722     * @return {this}
2723     */
2724    reset(softReset = false) {
2725      // If cancelled, revive the timer before rendering in order to have propertly composed tweens siblings
2726      reviveTimer(this);
2727      if (this._reversed && !this._reverse) this.reversed = false;
2728      // Rendering before updating the completed flag to prevent skips and to make sure the properties are not overridden
2729      // Setting the iterationTime at the end to force the rendering to happend backwards, otherwise calling .reset() on Timelines might not render children in the right order
2730      // NOTE: This is only required for Timelines and might be better to move to the Timeline class?
2731      this._iterationTime = this.iterationDuration;
2732      // Set tickMode to tickModes.FORCE to force rendering
2733      tick(this, 0, 1, ~~softReset, tickModes.FORCE);
2734      // Reset timer properties after revive / render to make sure the props are not updated again
2735      resetTimerProperties(this);
2736      // Also reset children properties
2737      if (this._hasChildren) {
2738        forEachChildren(this, resetTimerProperties);
2739      }
2740      return this;
2741    }
2742
2743    /**
2744     * @param  {Boolean} internalRender
2745     * @return {this}
2746     */
2747    init(internalRender = false) {
2748      this.fps = this._fps;
2749      this.speed = this._speed;
2750      // Manually calling .init() on timelines should render all children intial state
2751      // Forces all children to render once then render to 0 when reseted
2752      if (!internalRender && this._hasChildren) {
2753        tick(this, this.duration, 1, ~~internalRender, tickModes.FORCE);
2754      }
2755      this.reset(internalRender);
2756      // Make sure to set autoplay to false to child timers so it doesn't attempt to autoplay / link
2757      const autoplay = this._autoplay;
2758      if (autoplay === true) {
2759        this.resume();
2760      } else if (autoplay && !isUnd(/** @type {ScrollObserver} */(autoplay).linked)) {
2761        /** @type {ScrollObserver} */(autoplay).link(this);
2762      }
2763      return this;
2764    }
2765
2766    /** @return {this} */
2767    resetTime() {
2768      const timeScale = 1 / (this._speed * engine._speed);
2769      // TODO: See if we can safely use engine._lastTickTime here
2770      // if (!engine.reqId) engine.requestTick(now())
2771      // this._startTime = engine._lastTickTime - (this._currentTime + this._delay) * timeScale;
2772      this._startTime = now() - (this._currentTime + this._delay) * timeScale;
2773      return this;
2774    }
2775
2776    /** @return {this} */
2777    pause() {
2778      if (this.paused) return this;
2779      this.paused = true;
2780      this.onPause(this);
2781      return this;
2782    }
2783
2784    /** @return {this} */
2785    resume() {
2786      if (!this.paused) return this;
2787      this.paused = false;
2788      // We can safely imediatly render a timer that has no duration and no children
2789      if (this.duration <= minValue && !this._hasChildren) {
2790        tick(this, minValue, 0, 0, tickModes.FORCE);
2791      } else {
2792        if (!this._running) {
2793          addChild(engine, this);
2794          engine._hasChildren = true;
2795          this._running = true;
2796        }
2797        this.resetTime();
2798        // Forces the timer to advance by at least one frame when the next tick occurs
2799        this._startTime -= 12;
2800        engine.wake();
2801      }
2802      return this;
2803    }
2804
2805    /** @return {this} */
2806    restart() {
2807      return this.reset().resume();
2808    }
2809
2810    /**
2811     * @param  {Number} time
2812     * @param  {Boolean|Number} [muteCallbacks]
2813     * @param  {Boolean|Number} [internalRender]
2814     * @return {this}
2815     */
2816    seek(time, muteCallbacks = 0, internalRender = 0) {
2817      // Recompose the tween siblings in case the timer has been cancelled
2818      reviveTimer(this);
2819      // If you seek a completed animation, otherwise the next play will starts at 0
2820      this.completed = false;
2821      const isPaused = this.paused;
2822      this.paused = true;
2823      // timer, time, muteCallbacks, internalRender, tickMode
2824      tick(this, time + this._delay, ~~muteCallbacks, ~~internalRender, tickModes.AUTO);
2825      return isPaused ? this : this.resume();
2826    }
2827
2828    /** @return {this} */
2829    alternate() {
2830      const reversed = this._reversed;
2831      const count = this.iterationCount;
2832      const duration = this.iterationDuration;
2833      // Calculate the maximum iterations possible given the iteration duration
2834      const iterations = count === Infinity ? floor(maxValue / duration) : count;
2835      this._reversed = +(this._alternate && !(iterations % 2) ? reversed : !reversed);
2836      if (count === Infinity) {
2837        // Handle infinite loops to loop on themself
2838        this.iterationProgress = this._reversed ? 1 - this.iterationProgress : this.iterationProgress;
2839      } else {
2840        this.seek((duration * iterations) - this._currentTime);
2841      }
2842      this.resetTime();
2843      return this;
2844    }
2845
2846    /** @return {this} */
2847    play() {
2848      if (this._reversed) this.alternate();
2849      return this.resume();
2850    }
2851
2852    /** @return {this} */
2853    reverse() {
2854      if (!this._reversed) this.alternate();
2855      return this.resume();
2856    }
2857
2858    // TODO: Move all the animation / tweens / children related code to Animation / Timeline
2859
2860    /** @return {this} */
2861    cancel() {
2862      if (this._hasChildren) {
2863        forEachChildren(this, (/** @type {Renderable} */child) => child.cancel(), true);
2864      } else {
2865        forEachChildren(this, removeTweenSliblings);
2866      }
2867      this._cancelled = 1;
2868      // Pausing the timer removes it from the engine
2869      return this.pause();
2870    }
2871
2872    /**
2873     * @param  {Number} newDuration
2874     * @return {this}
2875     */
2876    stretch(newDuration) {
2877      const currentDuration = this.duration;
2878      const normlizedDuration = normalizeTime(newDuration);
2879      if (currentDuration === normlizedDuration) return this;
2880      const timeScale = newDuration / currentDuration;
2881      const isSetter = newDuration <= minValue;
2882      this.duration = isSetter ? minValue : normlizedDuration;
2883      this.iterationDuration = isSetter ? minValue : normalizeTime(this.iterationDuration * timeScale);
2884      this._offset *= timeScale;
2885      this._delay *= timeScale;
2886      this._loopDelay *= timeScale;
2887      return this;
2888    }
2889
2890   /**
2891     * Cancels the timer by seeking it back to 0 and reverting the attached scroller if necessary
2892     * @return {this}
2893     */
2894    revert() {
2895      tick(this, 0, 1, 0, tickModes.AUTO);
2896      const ap = /** @type {ScrollObserver} */(this._autoplay);
2897      if (ap && ap.linked && ap.linked === this) ap.revert();
2898      return this.cancel();
2899    }
2900
2901   /**
2902     * Imediatly completes the timer, cancels it and triggers the onComplete callback
2903     * @param  {Boolean|Number} [muteCallbacks]
2904     * @return {this}
2905     */
2906    complete(muteCallbacks = 0) {
2907      return this.seek(this.duration, muteCallbacks).cancel();
2908    }
2909
2910    /**
2911     * @typedef {this & {then: null}} ResolvedTimer
2912     */
2913
2914    /**
2915     * @param  {Callback<ResolvedTimer>} [callback]
2916     * @return Promise<this>
2917     */
2918    then(callback = noop) {
2919      const then = this.then;
2920      const onResolve = () => {
2921        // this.then = null prevents infinite recursion if returned by an async function
2922        // https://github.com/juliangarnierorg/anime-beta/issues/26
2923        this.then = null;
2924        callback(/** @type {ResolvedTimer} */(this));
2925        this.then = then;
2926        this._resolve = noop;
2927      };
2928      return new Promise(r => {
2929        this._resolve = () => r(onResolve());
2930        // Make sure to resolve imediatly if the timer has already completed
2931        if (this.completed) this._resolve();
2932        return this;
2933      });
2934    }
2935
2936  }
2937
2938  /**
2939   * @param {TimerParams} [parameters]
2940   * @return {Timer}
2941   */
2942  const createTimer = parameters => new Timer(parameters, null, 0).init();
2943
2944  
2945
2946  /**
2947   * @param  {DOMTargetsParam|TargetsParam} v
2948   * @return {NodeList|HTMLCollection}
2949   */
2950  function getNodeList(v) {
2951    const n = isStr(v) ? scope.root.querySelectorAll(v) : v;
2952    if (n instanceof NodeList || n instanceof HTMLCollection) return n;
2953  }
2954
2955  /**
2956   * @overload
2957   * @param  {DOMTargetsParam} targets
2958   * @return {DOMTargetsArray}
2959   *
2960   * @overload
2961   * @param  {JSTargetsParam} targets
2962   * @return {JSTargetsArray}
2963   *
2964   * @overload
2965   * @param  {TargetsParam} targets
2966   * @return {TargetsArray}
2967   *
2968   * @param  {DOMTargetsParam|JSTargetsParam|TargetsParam} targets
2969   */
2970  function parseTargets(targets) {
2971    if (isNil(targets)) return /** @type {TargetsArray} */([]);
2972    if (!isBrowser) return /** @type {JSTargetsArray} */(isArr(targets) && targets.flat(Infinity) || [targets]);
2973    if (isArr(targets)) {
2974      const flattened = targets.flat(Infinity);
2975      /** @type {TargetsArray} */
2976      const parsed = [];
2977      for (let i = 0, l = flattened.length; i < l; i++) {
2978        const item = flattened[i];
2979        if (!isNil(item)) {
2980          const nodeList = getNodeList(item);
2981          if (nodeList) {
2982            for (let j = 0, jl = nodeList.length; j < jl; j++) {
2983              const subItem = nodeList[j];
2984              if (!isNil(subItem)) {
2985                let isDuplicate = false;
2986                for (let k = 0, kl = parsed.length; k < kl; k++) {
2987                  if (parsed[k] === subItem) {
2988                    isDuplicate = true;
2989                    break;
2990                  }
2991                }
2992                if (!isDuplicate) {
2993                  parsed.push(subItem);
2994                }
2995              }
2996            }
2997          } else {
2998            let isDuplicate = false;
2999            for (let j = 0, jl = parsed.length; j < jl; j++) {
3000              if (parsed[j] === item) {
3001                isDuplicate = true;
3002                break;
3003              }
3004            }
3005            if (!isDuplicate) {
3006              parsed.push(item);
3007            }
3008          }
3009        }
3010      }
3011      return parsed;
3012    }
3013    const nodeList = getNodeList(targets);
3014    if (nodeList) return /** @type {DOMTargetsArray} */(Array.from(nodeList));
3015    return /** @type {TargetsArray} */([targets]);
3016  }
3017
3018  /**
3019   * @overload
3020   * @param  {DOMTargetsParam} targets
3021   * @return {DOMTargetsArray}
3022   *
3023   * @overload
3024   * @param  {JSTargetsParam} targets
3025   * @return {JSTargetsArray}
3026   *
3027   * @overload
3028   * @param  {TargetsParam} targets
3029   * @return {TargetsArray}
3030   *
3031   * @param  {DOMTargetsParam|JSTargetsParam|TargetsParam} targets
3032   */
3033  function registerTargets(targets) {
3034    const parsedTargetsArray = parseTargets(targets);
3035    const parsedTargetsLength = parsedTargetsArray.length;
3036    if (parsedTargetsLength) {
3037      for (let i = 0; i < parsedTargetsLength; i++) {
3038        const target = parsedTargetsArray[i];
3039        if (!target[isRegisteredTargetSymbol]) {
3040          target[isRegisteredTargetSymbol] = true;
3041          const isSvgType = isSvg(target);
3042          const isDom = /** @type {DOMTarget} */(target).nodeType || isSvgType;
3043          if (isDom) {
3044            target[isDomSymbol] = true;
3045            target[isSvgSymbol] = isSvgType;
3046            target[transformsSymbol] = {};
3047          }
3048        }
3049      }
3050    }
3051    return parsedTargetsArray;
3052  }
3053
3054  const angleUnitsMap = { 'deg': 1, 'rad': 180 / PI, 'turn': 360 };
3055  const convertedValuesCache = {};
3056
3057  
3058
3059  /**
3060   * @param  {DOMTarget} el
3061   * @param  {TweenDecomposedValue} decomposedValue
3062   * @param  {String} unit
3063   * @param  {Boolean} [force]
3064   * @return {TweenDecomposedValue}
3065   */
3066  const convertValueUnit = (el, decomposedValue, unit, force = false) => {
3067    const currentUnit = decomposedValue.u;
3068    const currentNumber = decomposedValue.n;
3069    if (decomposedValue.t === valueTypes.UNIT && currentUnit === unit) { // TODO: Check if checking against the same unit string is necessary
3070      return decomposedValue;
3071    }
3072    const cachedKey = currentNumber + currentUnit + unit;
3073    const cached = convertedValuesCache[cachedKey];
3074    if (!isUnd(cached) && !force) {
3075      decomposedValue.n = cached;
3076    } else {
3077      let convertedValue;
3078      if (currentUnit in angleUnitsMap) {
3079        convertedValue = currentNumber * angleUnitsMap[currentUnit] / angleUnitsMap[unit];
3080      } else {
3081        const baseline = 100;
3082        const tempEl = /** @type {DOMTarget} */(el.cloneNode());
3083        const parentNode = el.parentNode;
3084        const parentEl = (parentNode && (parentNode !== doc)) ? parentNode : doc.body;
3085        parentEl.appendChild(tempEl);
3086        const elStyle = tempEl.style;
3087        elStyle.width = baseline + currentUnit;
3088        const currentUnitWidth = /** @type {HTMLElement} */(tempEl).offsetWidth || baseline;
3089        elStyle.width = baseline + unit;
3090        const newUnitWidth = /** @type {HTMLElement} */(tempEl).offsetWidth || baseline;
3091        const factor = currentUnitWidth / newUnitWidth;
3092        parentEl.removeChild(tempEl);
3093        convertedValue = factor * currentNumber;
3094      }
3095      decomposedValue.n = convertedValue;
3096      convertedValuesCache[cachedKey] = convertedValue;
3097    }
3098    decomposedValue.t === valueTypes.UNIT;
3099    decomposedValue.u = unit;
3100    return decomposedValue;
3101  };
3102
3103  
3104
3105  /** @type {EasingFunction} */
3106  const none = t => t;
3107
3108  
3109
3110
3111  /** @type {PowerEasing} */
3112  const easeInPower = (p = 1.68) => t => pow(t, +p);
3113
3114  /**
3115   * @callback EaseType
3116   * @param {EasingFunction} Ease
3117   * @return {EasingFunction}
3118   */
3119
3120  /** @type {Record<String, EaseType>} */
3121  const easeTypes = {
3122    in: easeIn => t => easeIn(t),
3123    out: easeIn => t => 1 - easeIn(1 - t),
3124    inOut: easeIn => t => t < .5 ? easeIn(t * 2) / 2 : 1 - easeIn(t * -2 + 2) / 2,
3125    outIn: easeIn => t => t < .5 ? (1 - easeIn(1 - t * 2)) / 2 : (easeIn(t * 2 - 1) + 1) / 2,
3126  };
3127
3128  /**
3129   * Easing functions adapted and simplified from https://robertpenner.com/easing/
3130   * (c) 2001 Robert Penner
3131   */
3132
3133  const halfPI = PI / 2;
3134  const doublePI = PI * 2;
3135
3136  /** @type {Record<String, EasingFunctionWithParams|EasingFunction>} */
3137  const easeInFunctions = {
3138    [emptyString]: easeInPower,
3139    Quad: easeInPower(2),
3140    Cubic: easeInPower(3),
3141    Quart: easeInPower(4),
3142    Quint: easeInPower(5),
3143    /** @type {EasingFunction} */
3144    Sine: t => 1 - cos(t * halfPI),
3145    /** @type {EasingFunction} */
3146    Circ: t => 1 - sqrt(1 - t * t),
3147    /** @type {EasingFunction} */
3148    Expo: t => t ? pow(2, 10 * t - 10) : 0,
3149    /** @type {EasingFunction} */
3150    Bounce: t => {
3151      let pow2, b = 4;
3152      while (t < ((pow2 = pow(2, --b)) - 1) / 11);
3153      return 1 / pow(4, 3 - b) - 7.5625 * pow((pow2 * 3 - 2) / 22 - t, 2);
3154    },
3155    /** @type {BackEasing} */
3156    Back: (overshoot = 1.7) => t => (+overshoot + 1) * t * t * t - +overshoot * t * t,
3157    /** @type {ElasticEasing} */
3158    Elastic: (amplitude = 1, period = .3) => {
3159      const a = clamp$1(+amplitude, 1, 10);
3160      const p = clamp$1(+period, minValue, 2);
3161      const s = (p / doublePI) * asin(1 / a);
3162      const e = doublePI / p;
3163      return t => t === 0 || t === 1 ? t : -a * pow(2, -10 * (1 - t)) * sin(((1 - t) - s) * e);
3164    }
3165  };
3166
3167  /**
3168   * @typedef  {Object} EasesFunctions
3169   * @property {typeof none} linear
3170   * @property {typeof none} none
3171   * @property {PowerEasing} in
3172   * @property {PowerEasing} out
3173   * @property {PowerEasing} inOut
3174   * @property {PowerEasing} outIn
3175   * @property {EasingFunction} inQuad
3176   * @property {EasingFunction} outQuad
3177   * @property {EasingFunction} inOutQuad
3178   * @property {EasingFunction} outInQuad
3179   * @property {EasingFunction} inCubic
3180   * @property {EasingFunction} outCubic
3181   * @property {EasingFunction} inOutCubic
3182   * @property {EasingFunction} outInCubic
3183   * @property {EasingFunction} inQuart
3184   * @property {EasingFunction} outQuart
3185   * @property {EasingFunction} inOutQuart
3186   * @property {EasingFunction} outInQuart
3187   * @property {EasingFunction} inQuint
3188   * @property {EasingFunction} outQuint
3189   * @property {EasingFunction} inOutQuint
3190   * @property {EasingFunction} outInQuint
3191   * @property {EasingFunction} inSine
3192   * @property {EasingFunction} outSine
3193   * @property {EasingFunction} inOutSine
3194   * @property {EasingFunction} outInSine
3195   * @property {EasingFunction} inCirc
3196   * @property {EasingFunction} outCirc
3197   * @property {EasingFunction} inOutCirc
3198   * @property {EasingFunction} outInCirc
3199   * @property {EasingFunction} inExpo
3200   * @property {EasingFunction} outExpo
3201   * @property {EasingFunction} inOutExpo
3202   * @property {EasingFunction} outInExpo
3203   * @property {EasingFunction} inBounce
3204   * @property {EasingFunction} outBounce
3205   * @property {EasingFunction} inOutBounce
3206   * @property {EasingFunction} outInBounce
3207   * @property {BackEasing} inBack
3208   * @property {BackEasing} outBack
3209   * @property {BackEasing} inOutBack
3210   * @property {BackEasing} outInBack
3211   * @property {ElasticEasing} inElastic
3212   * @property {ElasticEasing} outElastic
3213   * @property {ElasticEasing} inOutElastic
3214   * @property {ElasticEasing} outInElastic
3215   */
3216
3217  const eases = (/*#__PURE__ */ (() => {
3218    const list = { linear: none, none: none };
3219    for (let type in easeTypes) {
3220      for (let name in easeInFunctions) {
3221        const easeIn = easeInFunctions[name];
3222        const easeType = easeTypes[type];
3223        list[type + name] = /** @type {EasingFunctionWithParams|EasingFunction} */(
3224          name === emptyString || name === 'Back' || name === 'Elastic' ?
3225          (a, b) => easeType(/** @type {EasingFunctionWithParams} */(easeIn)(a, b)) :
3226          easeType(/** @type {EasingFunction} */(easeIn))
3227        );
3228      }
3229    }
3230    return /** @type {EasesFunctions} */(list);
3231  })());
3232
3233  /** @type {Record<String, EasingFunction>} */
3234  const easesLookups = { linear: none, none: none };
3235
3236  /**
3237   * @param  {String} string
3238   * @return {EasingFunction}
3239   */
3240  const parseEaseString = (string) => {
3241    if (easesLookups[string]) return easesLookups[string];
3242    if (string.indexOf('(') <= -1) {
3243      const hasParams = easeTypes[string] || string.includes('Back') || string.includes('Elastic');
3244      const parsedFn = /** @type {EasingFunction} */(hasParams ? /** @type {EasingFunctionWithParams} */(eases[string])() : eases[string]);
3245      return parsedFn ? easesLookups[string] = parsedFn : none;
3246    } else {
3247      const split = string.slice(0, -1).split('(');
3248      const parsedFn = /** @type {EasingFunctionWithParams} */(eases[split[0]]);
3249      return parsedFn ? easesLookups[string] = parsedFn(...split[1].split(',')) : none;
3250    }
3251  };
3252
3253  const deprecated = ['steps(', 'irregular(', 'linear(', 'cubicBezier('];
3254
3255  /**
3256   * @param  {EasingParam} ease
3257   * @return {EasingFunction}
3258   */
3259  const parseEase = ease => {
3260    if (isStr(ease)) {
3261      for (let i = 0, l = deprecated.length; i < l; i++) {
3262        if (stringStartsWith(ease, deprecated[i])) {
3263          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}\``);
3264          return none;
3265        }
3266      }
3267    }
3268    const easeFunc = isFnc(ease) ? ease : isStr(ease) ? parseEaseString(/** @type {String} */(ease)) : none;
3269    return easeFunc;
3270  };
3271
3272  
3273
3274  // Defines decomposed values target objects only once and mutate their properties later to avoid GC
3275  // TODO: Maybe move the objects creation to values.js and use the decompose function to create the base object
3276  const fromTargetObject = createDecomposedValueTargetObject();
3277  const toTargetObject = createDecomposedValueTargetObject();
3278  const inlineStylesStore = {};
3279  const toFunctionStore = { func: null };
3280  const keyframesTargetArray = [null];
3281  const fastSetValuesArray = [null, null];
3282  /** @type {TweenKeyValue} */
3283  const keyObjectTarget = { to: null };
3284
3285  let tweenId = 0;
3286  let JSAnimationId = 0;
3287  let keyframes;
3288  /** @type {TweenParamsOptions & TweenValues} */
3289  let key;
3290
3291  /**
3292   * @param {DurationKeyframes | PercentageKeyframes} keyframes
3293   * @param {AnimationParams} parameters
3294   * @return {AnimationParams}
3295   */
3296  const generateKeyframes = (keyframes, parameters) => {
3297    /** @type {AnimationParams} */
3298    const properties = {};
3299    if (isArr(keyframes)) {
3300      const propertyNames = [].concat(.../** @type {DurationKeyframes} */(keyframes).map(key => Object.keys(key))).filter(isKey);
3301      for (let i = 0, l = propertyNames.length; i < l; i++) {
3302        const propName = propertyNames[i];
3303        const propArray = /** @type {DurationKeyframes} */(keyframes).map(key => {
3304          /** @type {TweenKeyValue} */
3305          const newKey = {};
3306          for (let p in key) {
3307            const keyValue = /** @type {TweenPropValue} */(key[p]);
3308            if (isKey(p)) {
3309              if (p === propName) {
3310                newKey.to = keyValue;
3311              }
3312            } else {
3313              newKey[p] = keyValue;
3314            }
3315          }
3316          return newKey;
3317        });
3318        properties[propName] = /** @type {ArraySyntaxValue} */(propArray);
3319      }
3320
3321    } else {
3322      const totalDuration = /** @type {Number} */(setValue(parameters.duration, globals.defaults.duration));
3323      const keys = Object.keys(keyframes)
3324      .map(key => { return {o: parseFloat(key) / 100, p: keyframes[key]} })
3325      .sort((a, b) => a.o - b.o);
3326      keys.forEach(key => {
3327        const offset = key.o;
3328        const prop = key.p;
3329        for (let name in prop) {
3330          if (isKey(name)) {
3331            let propArray = /** @type {Array} */(properties[name]);
3332            if (!propArray) propArray = properties[name] = [];
3333            const duration = offset * totalDuration;
3334            let length = propArray.length;
3335            let prevKey = propArray[length - 1];
3336            const keyObj = { to: prop[name] };
3337            let durProgress = 0;
3338            for (let i = 0; i < length; i++) {
3339              durProgress += propArray[i].duration;
3340            }
3341            if (length === 1) {
3342              keyObj.from = prevKey.to;
3343            }
3344            if (prop.ease) {
3345              keyObj.ease = prop.ease;
3346            }
3347            keyObj.duration = duration - (length ? durProgress : 0);
3348            propArray.push(keyObj);
3349          }
3350        }
3351        return key;
3352      });
3353
3354      for (let name in properties) {
3355        const propArray = /** @type {Array} */(properties[name]);
3356        let prevEase;
3357        // let durProgress = 0
3358        for (let i = 0, l = propArray.length; i < l; i++) {
3359          const prop = propArray[i];
3360          // Emulate WAPPI easing parameter position
3361          const currentEase = prop.ease;
3362          prop.ease = prevEase ? prevEase : undefined;
3363          prevEase = currentEase;
3364          // durProgress += prop.duration;
3365          // if (i === l - 1 && durProgress !== totalDuration) {
3366          //   propArray.push({ from: prop.to, ease: prop.ease, duration: totalDuration - durProgress })
3367          // }
3368        }
3369        if (!propArray[0].duration) {
3370          propArray.shift();
3371        }
3372      }
3373
3374    }
3375
3376    return properties;
3377  };
3378
3379  class JSAnimation extends Timer {
3380    /**
3381     * @param {TargetsParam} targets
3382     * @param {AnimationParams} parameters
3383     * @param {Timeline} [parent]
3384     * @param {Number} [parentPosition]
3385     * @param {Boolean} [fastSet=false]
3386     * @param {Number} [index=0]
3387     * @param {Number} [length=0]
3388     */
3389    constructor(
3390      targets,
3391      parameters,
3392      parent,
3393      parentPosition,
3394      fastSet = false,
3395      index = 0,
3396      length = 0
3397    ) {
3398
3399      super(/** @type {TimerParams & AnimationParams} */(parameters), parent, parentPosition);
3400
3401      ++JSAnimationId;
3402
3403      const parsedTargets = registerTargets(targets);
3404      const targetsLength = parsedTargets.length;
3405
3406      // If the parameters object contains a "keyframes" property, convert all the keyframes values to regular properties
3407
3408      const kfParams = /** @type {AnimationParams} */(parameters).keyframes;
3409      const params = /** @type {AnimationParams} */(kfParams ? mergeObjects(generateKeyframes(/** @type {DurationKeyframes} */(kfParams), parameters), parameters) : parameters);
3410
3411      const {
3412        id,
3413        delay,
3414        duration,
3415        ease,
3416        playbackEase,
3417        modifier,
3418        composition,
3419        onRender,
3420      } = params;
3421
3422      const animDefaults = parent ? parent.defaults : globals.defaults;
3423      const animEase = setValue(ease, animDefaults.ease);
3424      const animPlaybackEase = setValue(playbackEase, animDefaults.playbackEase);
3425      const parsedAnimPlaybackEase = animPlaybackEase ? parseEase(animPlaybackEase) : null;
3426      const hasSpring = !isUnd(/** @type {Spring} */(animEase).ease);
3427      const tEasing = hasSpring ? /** @type {Spring} */(animEase).ease : setValue(ease, parsedAnimPlaybackEase ? 'linear' : animDefaults.ease);
3428      const tDuration = hasSpring ? /** @type {Spring} */(animEase).settlingDuration : setValue(duration, animDefaults.duration);
3429      const tDelay = setValue(delay, animDefaults.delay);
3430      const tModifier = modifier || animDefaults.modifier;
3431      // If no composition is defined and the targets length is high (>= 1000) set the composition to 'none' (0) for faster tween creation
3432      const tComposition = isUnd(composition) && targetsLength >= K ? compositionTypes.none : !isUnd(composition) ? composition : animDefaults.composition;
3433      // const absoluteOffsetTime = this._offset;
3434      const absoluteOffsetTime = this._offset + (parent ? parent._offset : 0);
3435      // This allows targeting the current animation in the spring onComplete callback
3436      if (hasSpring) /** @type {Spring} */(animEase).parent = this;
3437
3438      let iterationDuration = NaN;
3439      let iterationDelay = NaN;
3440      let animationAnimationLength = 0;
3441      let shouldTriggerRender = 0;
3442
3443      for (let targetIndex = 0; targetIndex < targetsLength; targetIndex++) {
3444
3445        const target = parsedTargets[targetIndex];
3446        const ti = index || targetIndex;
3447        const tl = length || targetsLength;
3448
3449        let lastTransformGroupIndex = NaN;
3450        let lastTransformGroupLength = NaN;
3451
3452        for (let p in params) {
3453
3454          if (isKey(p)) {
3455
3456            const tweenType = getTweenType(target, p);
3457
3458            const propName = sanitizePropertyName(p, target, tweenType);
3459
3460            let propValue = params[p];
3461
3462            const isPropValueArray = isArr(propValue);
3463
3464            if (fastSet && !isPropValueArray) {
3465              fastSetValuesArray[0] = propValue;
3466              fastSetValuesArray[1] = propValue;
3467              propValue = fastSetValuesArray;
3468            }
3469
3470            // TODO: Allow nested keyframes inside ObjectValue value (prop: { to: [.5, 1, .75, 2, 3] })
3471            // Normalize property values to valid keyframe syntax:
3472            // [x, y] to [{to: [x, y]}] or {to: x} to [{to: x}] or keep keys syntax [{}, {}, {}...]
3473            // const keyframes = isArr(propValue) ? propValue.length === 2 && !isObj(propValue[0]) ? [{ to: propValue }] : propValue : [propValue];
3474            if (isPropValueArray) {
3475              const arrayLength = /** @type {Array} */(propValue).length;
3476              const isNotObjectValue = !isObj(propValue[0]);
3477              // Convert [x, y] to [{to: [x, y]}]
3478              if (arrayLength === 2 && isNotObjectValue) {
3479                keyObjectTarget.to = /** @type {TweenParamValue} */(/** @type {unknown} */(propValue));
3480                keyframesTargetArray[0] = keyObjectTarget;
3481                keyframes = keyframesTargetArray;
3482              // Convert [x, y, z] to [[x, y], z]
3483              } else if (arrayLength > 2 && isNotObjectValue) {
3484                keyframes = [];
3485                /** @type {Array.<Number>} */(propValue).forEach((v, i) => {
3486                  if (!i) {
3487                    fastSetValuesArray[0] = v;
3488                  } else if (i === 1) {
3489                    fastSetValuesArray[1] = v;
3490                    keyframes.push(fastSetValuesArray);
3491                  } else {
3492                    keyframes.push(v);
3493                  }
3494                });
3495              } else {
3496                keyframes = /** @type {Array.<TweenKeyValue>} */(propValue);
3497              }
3498            } else {
3499              keyframesTargetArray[0] = propValue;
3500              keyframes = keyframesTargetArray;
3501            }
3502
3503            let siblings = null;
3504            let prevTween = null;
3505            let firstTweenChangeStartTime = NaN;
3506            let lastTweenChangeEndTime = 0;
3507            let tweenIndex = 0;
3508
3509            for (let l = keyframes.length; tweenIndex < l; tweenIndex++) {
3510
vendor: 2,638 bytes, lines 3511-3552
3511              const keyframe = keyframes[tweenIndex];
3512
3513              if (isObj(keyframe)) {
3514                key = keyframe;
3515              } else {
3516                keyObjectTarget.to = /** @type {TweenParamValue} */(keyframe);
3517                key = keyObjectTarget;
3518              }
3519
3520              toFunctionStore.func = null;
3521
3522              const computedToValue = getFunctionValue(key.to, target, ti, tl, toFunctionStore);
3523
3524              let tweenToValue;
3525              // Allows function based values to return an object syntax value ({to: v})
3526              if (isObj(computedToValue) && !isUnd(computedToValue.to)) {
3527                key = computedToValue;
3528                tweenToValue = computedToValue.to;
3529              } else {
3530                tweenToValue = computedToValue;
3531              }
3532              const tweenFromValue = getFunctionValue(key.from, target, ti, tl);
3533              const easeToParse = key.ease || tEasing;
3534
3535              const easeFunctionResult = getFunctionValue(easeToParse, target, ti, tl);
3536              const keyEasing = isFnc(easeFunctionResult) || isStr(easeFunctionResult) ? easeFunctionResult : easeToParse;
3537
3538              const hasSpring = !isUnd(keyEasing) && !isUnd(/** @type {Spring} */(keyEasing).ease);
3539              const tweenEasing = hasSpring ? /** @type {Spring} */(keyEasing).ease : keyEasing;
3540              // Calculate default individual keyframe duration by dividing the tl of keyframes
3541              const tweenDuration = hasSpring ? /** @type {Spring} */(keyEasing).settlingDuration : getFunctionValue(setValue(key.duration, (l > 1 ? getFunctionValue(tDuration, target, ti, tl) / l : tDuration)), target, ti, tl);
3542              // Default delay value should only be applied to the first tween
3543              const tweenDelay = getFunctionValue(setValue(key.delay, (!tweenIndex ? tDelay : 0)), target, ti, tl);
3544              const computedComposition = getFunctionValue(setValue(key.composition, tComposition), target, ti, tl);
3545              const tweenComposition = isNum(computedComposition) ? computedComposition : compositionTypes[computedComposition];
3546              // Modifiers are treated differently and don't accept function based value to prevent having to pass a function wrapper
3547              const tweenModifier = key.modifier || tModifier;
3548              const hasFromvalue = !isUnd(tweenFromValue);
3549              const hasToValue = !isUnd(tweenToValue);
3550              const isFromToArray = isArr(tweenToValue);
3551              const isFromToValue = isFromToArray || (hasFromvalue && hasToValue);
3552              const tweenStartTime = prevTween ? lastTweenChangeEndTime + tween
vendor: 6,531 bytes, lines 3552-3660
3552Delay : tweenDelay;
3553              // Rounding is necessary here to minimize floating point errors when working in seconds
3554              const absoluteStartTime = round$1(absoluteOffsetTime + tweenStartTime, 12);
3555
3556              // Force a onRender callback if the animation contains at least one from value and autoplay is set to false
3557              if (!shouldTriggerRender && (hasFromvalue || isFromToArray)) shouldTriggerRender = 1;
3558
3559              let prevSibling = prevTween;
3560
3561              if (tweenComposition !== compositionTypes.none) {
3562                if (!siblings) siblings = getTweenSiblings(target, propName);
3563                let nextSibling = siblings._head;
3564                // Iterate trough all the next siblings until we find a sibling with an equal or inferior start time
3565                while (nextSibling && !nextSibling._isOverridden && nextSibling._absoluteStartTime <= absoluteStartTime) {
3566                  prevSibling = nextSibling;
3567                  nextSibling = nextSibling._nextRep;
3568                  // Overrides all the next siblings if the next sibling starts at the same time of after as the new tween start time
3569                  if (nextSibling && nextSibling._absoluteStartTime >= absoluteStartTime) {
3570                    while (nextSibling) {
3571                      overrideTween(nextSibling);
3572                      // This will ends both the current while loop and the upper one once all the next sibllings have been overriden
3573                      nextSibling = nextSibling._nextRep;
3574                    }
3575                  }
3576                }
3577              }
3578
3579              // Decompose values
3580              if (isFromToValue) {
3581                decomposeRawValue(isFromToArray ? getFunctionValue(tweenToValue[0], target, ti, tl) : tweenFromValue, fromTargetObject);
3582                decomposeRawValue(isFromToArray ? getFunctionValue(tweenToValue[1], target, ti, tl, toFunctionStore) : tweenToValue, toTargetObject);
3583                // Needed to force an inline style registration
3584                const originalValue = getOriginalAnimatableValue(target, propName, tweenType, inlineStylesStore);
3585                if (fromTargetObject.t === valueTypes.NUMBER) {
3586                  if (prevSibling) {
3587                    if (prevSibling._valueType === valueTypes.UNIT) {
3588                      fromTargetObject.t = valueTypes.UNIT;
3589                      fromTargetObject.u = prevSibling._unit;
3590                    }
3591                  } else {
3592                    decomposeRawValue(
3593                      originalValue,
3594                      decomposedOriginalValue
3595                    );
3596                    if (decomposedOriginalValue.t === valueTypes.UNIT) {
3597                      fromTargetObject.t = valueTypes.UNIT;
3598                      fromTargetObject.u = decomposedOriginalValue.u;
3599                    }
3600                  }
3601                }
3602              } else {
3603                if (hasToValue) {
3604                  decomposeRawValue(tweenToValue, toTargetObject);
3605                } else {
3606                  if (prevTween) {
3607                    decomposeTweenValue(prevTween, toTargetObject);
3608                  } else {
3609                    // 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
3610                    decomposeRawValue(parent && prevSibling && prevSibling.parent.parent === parent ? prevSibling._value :
3611                    getOriginalAnimatableValue(target, propName, tweenType, inlineStylesStore), toTargetObject);
3612                  }
3613                }
3614                if (hasFromvalue) {
3615                  decomposeRawValue(tweenFromValue, fromTargetObject);
3616                } else {
3617                  if (prevTween) {
3618                    decomposeTweenValue(prevTween, fromTargetObject);
3619                  } else {
3620                    decomposeRawValue(parent && prevSibling && prevSibling.parent.parent === parent ? prevSibling._value :
3621                    // 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
3622                    getOriginalAnimatableValue(target, propName, tweenType, inlineStylesStore), fromTargetObject);
3623                  }
3624                }
3625              }
3626
3627              // Apply operators
3628              if (fromTargetObject.o) {
3629                fromTargetObject.n = getRelativeValue(
3630                  !prevSibling ? decomposeRawValue(
3631                    getOriginalAnimatableValue(target, propName, tweenType, inlineStylesStore),
3632                    decomposedOriginalValue
3633                  ).n : prevSibling._toNumber,
3634                  fromTargetObject.n,
3635                  fromTargetObject.o
3636                );
3637              }
3638
3639              if (toTargetObject.o) {
3640                toTargetObject.n = getRelativeValue(fromTargetObject.n, toTargetObject.n, toTargetObject.o);
3641              }
3642
3643              // Values omogenisation in cases of type difference between "from" and "to"
3644              if (fromTargetObject.t !== toTargetObject.t) {
3645                if (fromTargetObject.t === valueTypes.COMPLEX || toTargetObject.t === valueTypes.COMPLEX) {
3646                  const complexValue = fromTargetObject.t === valueTypes.COMPLEX ? fromTargetObject : toTargetObject;
3647                  const notComplexValue = fromTargetObject.t === valueTypes.COMPLEX ? toTargetObject : fromTargetObject;
3648                  notComplexValue.t = valueTypes.COMPLEX;
3649                  notComplexValue.s = cloneArray(complexValue.s);
3650                  notComplexValue.d = complexValue.d.map(() => notComplexValue.n);
3651                } else if (fromTargetObject.t === valueTypes.UNIT || toTargetObject.t === valueTypes.UNIT) {
3652                  const unitValue = fromTargetObject.t === valueTypes.UNIT ? fromTargetObject : toTargetObject;
3653                  const notUnitValue = fromTargetObject.t === valueTypes.UNIT ? toTargetObject : fromTargetObject;
3654                  notUnitValue.t = valueTypes.UNIT;
3655                  notUnitValue.u = unitValue.u;
3656                } else if (fromTargetObject.t === valueTypes.COLOR || toTargetObject.t === valueTypes.COLOR) {
3657                  const colorValue = fromTargetObject.t === valueTypes.COLOR ? fromTargetObject : toTargetObject;
3658                  const notColorValue = fromTargetObject.t === valueTypes.COLOR ? toTargetObject : fromTargetObject;
3659                  notColorValue.t = valueTypes.COLOR;
3660                  notColorValue.s = colorValue.s;
vendor: 5,017 bytes, lines 3661-3769
3661                  notColorValue.d = [0, 0, 0, 1];
3662                }
3663              }
3664
3665              // Unit conversion
3666              if (fromTargetObject.u !== toTargetObject.u) {
3667                let valueToConvert = toTargetObject.u ? fromTargetObject : toTargetObject;
3668                valueToConvert = convertValueUnit(/** @type {DOMTarget} */(target), valueToConvert, toTargetObject.u ? toTargetObject.u : fromTargetObject.u, false);
3669                // TODO:
3670                // convertValueUnit(target, to.u ? from : to, to.u ? to.u : from.u);
3671              }
3672
3673              // Fill in non existing complex values
3674              if (toTargetObject.d && fromTargetObject.d && (toTargetObject.d.length !== fromTargetObject.d.length)) {
3675                const longestValue = fromTargetObject.d.length > toTargetObject.d.length ? fromTargetObject : toTargetObject;
3676                const shortestValue = longestValue === fromTargetObject ? toTargetObject : fromTargetObject;
3677                // TODO: Check if n should be used instead of 0 for default complex values
3678                shortestValue.d = longestValue.d.map((/** @type {Number} */_, /** @type {Number} */i) => isUnd(shortestValue.d[i]) ? 0 : shortestValue.d[i]);
3679                shortestValue.s = cloneArray(longestValue.s);
3680              }
3681
3682              // Tween factory
3683
3684              // Rounding is necessary here to minimize floating point errors when working in seconds
3685              const tweenUpdateDuration = round$1(+tweenDuration || minValue, 12);
3686
3687              // Copy the value of the iniline style if it exist and imediatly nullify it to prevents false positive on other targets
3688              let inlineValue = inlineStylesStore[propName];
3689              if (!isNil(inlineValue)) inlineStylesStore[propName] = null;
3690
3691              /** @type {Tween} */
3692              const tween = {
3693                parent: this,
3694                id: tweenId++,
3695                property: propName,
3696                target: target,
3697                _value: null,
3698                _func: toFunctionStore.func,
3699                _ease: parseEase(tweenEasing),
3700                _fromNumbers: cloneArray(fromTargetObject.d),
3701                _toNumbers: cloneArray(toTargetObject.d),
3702                _strings: cloneArray(toTargetObject.s),
3703                _fromNumber: fromTargetObject.n,
3704                _toNumber: toTargetObject.n,
3705                _numbers: cloneArray(fromTargetObject.d), // For additive tween and animatables
3706                _number: fromTargetObject.n, // For additive tween and animatables
3707                _unit: toTargetObject.u,
3708                _modifier: tweenModifier,
3709                _currentTime: 0,
3710                _startTime: tweenStartTime,
3711                _delay: +tweenDelay,
3712                _updateDuration: tweenUpdateDuration,
3713                _changeDuration: tweenUpdateDuration,
3714                _absoluteStartTime: absoluteStartTime,
3715                // NOTE: Investigate bit packing to stores ENUM / BOOL
3716                _tweenType: tweenType,
3717                _valueType: toTargetObject.t,
3718                _composition: tweenComposition,
3719                _isOverlapped: 0,
3720                _isOverridden: 0,
3721                _renderTransforms: 0,
3722                _inlineValue: inlineValue,
3723                _prevRep: null, // For replaced tween
3724                _nextRep: null, // For replaced tween
3725                _prevAdd: null, // For additive tween
3726                _nextAdd: null, // For additive tween
3727                _prev: null,
3728                _next: null,
3729              };
3730
3731              if (tweenComposition !== compositionTypes.none) {
3732                composeTween(tween, siblings);
3733              }
3734
3735              if (isNaN(firstTweenChangeStartTime)) {
3736                firstTweenChangeStartTime = tween._startTime;
3737              }
3738              // Rounding is necessary here to minimize floating point errors when working in seconds
3739              lastTweenChangeEndTime = round$1(tweenStartTime + tweenUpdateDuration, 12);
3740              prevTween = tween;
3741              animationAnimationLength++;
3742
3743              addChild(this, tween);
3744
3745            }
3746
3747            // Update animation timings with the added tweens properties
3748
3749            if (isNaN(iterationDelay) || firstTweenChangeStartTime < iterationDelay) {
3750              iterationDelay = firstTweenChangeStartTime;
3751            }
3752
3753            if (isNaN(iterationDuration) || lastTweenChangeEndTime > iterationDuration) {
3754              iterationDuration = lastTweenChangeEndTime;
3755            }
3756
3757            // TODO: Find a way to inline tween._renderTransforms = 1 here
3758            if (tweenType === tweenTypes.TRANSFORM) {
3759              lastTransformGroupIndex = animationAnimationLength - tweenIndex;
3760              lastTransformGroupLength = animationAnimationLength;
3761            }
3762
3763          }
3764
3765        }
3766
3767        // Set _renderTransforms to last transform property to correctly render the transforms list
3768        if (!isNaN(lastTransformGroupIndex)) {
3769          let i = 0;
vendor: 14,267 bytes, lines 3770-4163
3770          forEachChildren(this, (/** @type {Tween} */tween) => {
3771            if (i >= lastTransformGroupIndex && i < lastTransformGroupLength) {
3772              tween._renderTransforms = 1;
3773              if (tween._composition === compositionTypes.blend) {
3774                forEachChildren(additive.animation, (/** @type {Tween} */additiveTween) => {
3775                  if (additiveTween.id === tween.id) {
3776                    additiveTween._renderTransforms = 1;
3777                  }
3778                });
3779              }
3780            }
3781            i++;
3782          });
3783        }
3784
3785      }
3786
3787      if (!targetsLength) {
3788        console.warn(`No target found. Make sure the element you're trying to animate is accessible before creating your animation.`);
3789      }
3790
3791      if (iterationDelay) {
3792        forEachChildren(this, (/** @type {Tween} */tween) => {
3793          // If (startTime - delay) equals 0, this means the tween is at the begining of the animation so we need to trim the delay too
3794          if (!(tween._startTime - tween._delay)) {
3795            tween._delay -= iterationDelay;
3796          }
3797          tween._startTime -= iterationDelay;
3798        });
3799        iterationDuration -= iterationDelay;
3800      } else {
3801        iterationDelay = 0;
3802      }
3803
3804      // Prevents iterationDuration to be NaN if no valid animatable props have been provided
3805      // Prevents _iterationCount to be NaN if no valid animatable props have been provided
3806      if (!iterationDuration) {
3807        iterationDuration = minValue;
3808        this.iterationCount = 0;
3809      }
3810      /** @type {TargetsArray} */
3811      this.targets = parsedTargets;
3812      /** @type {String|Number} */
3813      this.id = !isUnd(id) ? id : JSAnimationId;
3814      /** @type {Number} */
3815      this.duration = iterationDuration === minValue ? minValue : clampInfinity(((iterationDuration + this._loopDelay) * this.iterationCount) - this._loopDelay) || minValue;
3816      /** @type {Callback<this>} */
3817      this.onRender = onRender || animDefaults.onRender;
3818      /** @type {EasingFunction} */
3819      this._ease = parsedAnimPlaybackEase;
3820      /** @type {Number} */
3821      this._delay = iterationDelay;
3822      // NOTE: I'm keeping delay values separated from offsets in timelines because delays can override previous tweens and it could be confusing to debug a timeline with overridden tweens and no associated visible delays.
3823      // this._delay = parent ? 0 : iterationDelay;
3824      // this._offset += parent ? iterationDelay : 0;
3825      /** @type {Number} */
3826      this.iterationDuration = iterationDuration;
3827
3828      if (!this._autoplay && shouldTriggerRender) this.onRender(this);
3829    }
3830
3831    /**
3832     * @param  {Number} newDuration
3833     * @return {this}
3834     */
3835    stretch(newDuration) {
3836      const currentDuration = this.duration;
3837      if (currentDuration === normalizeTime(newDuration)) return this;
3838      const timeScale = newDuration / currentDuration;
3839      // NOTE: Find a better way to handle the stretch of an animation after stretch = 0
3840      forEachChildren(this, (/** @type {Tween} */tween) => {
3841        // Rounding is necessary here to minimize floating point errors
3842        tween._updateDuration = normalizeTime(tween._updateDuration * timeScale);
3843        tween._changeDuration = normalizeTime(tween._changeDuration * timeScale);
3844        tween._currentTime *= timeScale;
3845        tween._startTime *= timeScale;
3846        tween._absoluteStartTime *= timeScale;
3847      });
3848      return super.stretch(newDuration);
3849    }
3850
3851    /**
3852     * @return {this}
3853     */
3854    refresh() {
3855      forEachChildren(this, (/** @type {Tween} */tween) => {
3856        const tweenFunc = tween._func;
3857        if (tweenFunc) {
3858          const ogValue = getOriginalAnimatableValue(tween.target, tween.property, tween._tweenType);
3859          decomposeRawValue(ogValue, decomposedOriginalValue);
3860          // TODO: Check for from / to Array based values here,
3861          decomposeRawValue(tweenFunc(), toTargetObject);
3862          tween._fromNumbers = cloneArray(decomposedOriginalValue.d);
3863          tween._fromNumber = decomposedOriginalValue.n;
3864          tween._toNumbers = cloneArray(toTargetObject.d);
3865          tween._strings = cloneArray(toTargetObject.s);
3866          // Make sure to apply relative operators https://github.com/juliangarnier/anime/issues/1025
3867          tween._toNumber = toTargetObject.o ? getRelativeValue(decomposedOriginalValue.n, toTargetObject.n, toTargetObject.o) : toTargetObject.n;
3868        }
3869      });
3870      // This forces setter animations to render once
3871      if (this.duration === minValue) this.restart();
3872      return this;
3873    }
3874
3875    /**
3876     * Cancel the animation and revert all the values affected by this animation to their original state
3877     * @return {this}
3878     */
3879    revert() {
3880      super.revert();
3881      return cleanInlineStyles(this);
3882    }
3883
3884    /**
3885     * @typedef {this & {then: null}} ResolvedJSAnimation
3886     */
3887
3888    /**
3889     * @param  {Callback<ResolvedJSAnimation>} [callback]
3890     * @return Promise<this>
3891     */
3892    then(callback) {
3893      return super.then(callback);
3894    }
3895
3896  }
3897
3898  /**
3899   * @param {TargetsParam} targets
3900   * @param {AnimationParams} parameters
3901   * @return {JSAnimation}
3902   */
3903  const animate = (targets, parameters) => new JSAnimation(targets, parameters, null, 0, false).init();
3904
3905  
3906
3907  
3908
3909  const WAAPIAnimationsLookups = {
3910    _head: null,
3911    _tail: null,
3912  };
3913
3914  /**
3915   * @param {DOMTarget} $el
3916   * @param {String} [property]
3917   * @param {WAAPIAnimation} [parent]
3918   * @return {globalThis.Animation}
3919   */
3920  const removeWAAPIAnimation = ($el, property, parent) => {
3921    let nextLookup = WAAPIAnimationsLookups._head;
3922    let anim;
3923    while (nextLookup) {
3924      const next = nextLookup._next;
3925      const matchTarget = nextLookup.$el === $el;
3926      const matchProperty = !property || nextLookup.property === property;
3927      const matchParent = !parent || nextLookup.parent === parent;
3928      if (matchTarget && matchProperty && matchParent) {
3929        anim = nextLookup.animation;
3930        try { anim.commitStyles(); } catch {}      anim.cancel();
3931        removeChild(WAAPIAnimationsLookups, nextLookup);
3932        const lookupParent = nextLookup.parent;
3933        if (lookupParent) {
3934          lookupParent._completed++;
3935          if (lookupParent.animations.length === lookupParent._completed) {
3936            lookupParent.completed = true;
3937            lookupParent.paused = true;
3938            if (!lookupParent.muteCallbacks) {
3939              lookupParent.onComplete(lookupParent);
3940              lookupParent._resolve(lookupParent);
3941            }
3942          }
3943        }
3944      }
3945      nextLookup = next;
3946    }
3947    return anim;
3948  };
3949
3950  /**
3951   * @param {WAAPIAnimation} parent
3952   * @param {DOMTarget} $el
3953   * @param {String} property
3954   * @param {PropertyIndexedKeyframes} keyframes
3955   * @param {KeyframeAnimationOptions} params
3956   * @retun {globalThis.Animation}
3957   */
3958  const addWAAPIAnimation = (parent, $el, property, keyframes, params) => {
3959    const animation = $el.animate(keyframes, params);
3960    const animTotalDuration = params.delay + (+params.duration * params.iterations);
3961    animation.playbackRate = parent._speed;
3962    if (parent.paused) animation.pause();
3963    if (parent.duration < animTotalDuration) {
3964      parent.duration = animTotalDuration;
3965      parent.controlAnimation = animation;
3966    }
3967    parent.animations.push(animation);
3968    removeWAAPIAnimation($el, property);
3969    addChild(WAAPIAnimationsLookups, { parent, animation, $el, property, _next: null, _prev: null });
3970    const handleRemove = () => { removeWAAPIAnimation($el, property, parent); };
3971    animation.oncancel = handleRemove;
3972    animation.onremove = handleRemove;
3973    if (!parent.persist) {
3974      animation.onfinish = handleRemove;
3975    }
3976    return animation;
3977  };
3978
3979  
3980
3981  
3982
3983  /**
3984   * @overload
3985   * @param  {DOMTargetSelector} targetSelector
3986   * @param  {String} propName
3987   * @return {String}
3988   *
3989   * @overload
3990   * @param  {JSTargetsParam} targetSelector
3991   * @param  {String} propName
3992   * @return {Number|String}
3993   *
3994   * @overload
3995   * @param  {DOMTargetsParam} targetSelector
3996   * @param  {String} propName
3997   * @param  {String} unit
3998   * @return {String}
3999   *
4000   * @overload
4001   * @param  {TargetsParam} targetSelector
4002   * @param  {String} propName
4003   * @param  {Boolean} unit
4004   * @return {Number}
4005   *
4006   * @param  {TargetsParam} targetSelector
4007   * @param  {String} propName
4008   * @param  {String|Boolean} [unit]
4009   */
4010  function get(targetSelector, propName, unit) {
4011    const targets = registerTargets(targetSelector);
4012    if (!targets.length) return;
4013    const [ target ] = targets;
4014    const tweenType = getTweenType(target, propName);
4015    const normalizePropName = sanitizePropertyName(propName, target, tweenType);
4016    let originalValue = getOriginalAnimatableValue(target, normalizePropName);
4017    if (isUnd(unit)) {
4018      return originalValue;
4019    } else {
4020      decomposeRawValue(originalValue, decomposedOriginalValue);
4021      if (decomposedOriginalValue.t === valueTypes.NUMBER || decomposedOriginalValue.t === valueTypes.UNIT) {
4022        if (unit === false) {
4023          return decomposedOriginalValue.n;
4024        } else {
4025          const convertedValue = convertValueUnit(/** @type {DOMTarget} */(target), decomposedOriginalValue, /** @type {String} */(unit), false);
4026          return `${round$1(convertedValue.n, globals.precision)}${convertedValue.u}`;
4027        }
4028      }
4029    }
4030  }
4031
4032  /**
4033   * @param  {TargetsParam} targets
4034   * @param  {AnimationParams} parameters
4035   * @return {JSAnimation}
4036   */
4037  const set = (targets, parameters) => {
4038    if (isUnd(parameters)) return;
4039    parameters.duration = minValue;
4040    // Do not overrides currently active tweens by default
4041    parameters.composition = setValue(parameters.composition, compositionTypes.none);
4042    // Skip init() and force rendering by playing the animation
4043    return new JSAnimation(targets, parameters, null, 0, true).resume();
4044  };
4045
4046  /**
4047   * @param  {TargetsParam} targets
4048   * @param  {Renderable|WAAPIAnimation} [renderable]
4049   * @param  {String} [propertyName]
4050   * @return {TargetsArray}
4051   */
4052  const remove = (targets, renderable, propertyName) => {
4053    const targetsArray = parseTargets(targets);
4054    for (let i = 0, l = targetsArray.length; i < l; i++) {
4055      removeWAAPIAnimation(
4056        /** @type {DOMTarget}  */(targetsArray[i]),
4057        propertyName,
4058        renderable && /** @type {WAAPIAnimation} */(renderable).controlAnimation && /** @type {WAAPIAnimation} */(renderable),
4059      );
4060    }
4061    removeTargetsFromRenderable(
4062      targetsArray,
4063      /** @type {Renderable} */(renderable),
4064      propertyName
4065    );
4066    return targetsArray;
4067  };
4068
4069  
4070
4071  
4072
4073  /**
4074   * Timeline's children offsets positions parser
4075   * @param  {Timeline} timeline
4076   * @param  {String} timePosition
4077   * @return {Number}
4078   */
4079  const getPrevChildOffset = (timeline, timePosition) => {
4080    if (stringStartsWith(timePosition, '<')) {
4081      const goToPrevAnimationOffset = timePosition[1] === '<';
4082      const prevAnimation = /** @type {Tickable} */(timeline._tail);
4083      const prevOffset = prevAnimation ? prevAnimation._offset + prevAnimation._delay : 0;
4084      return goToPrevAnimationOffset ? prevOffset : prevOffset + prevAnimation.duration;
4085    }
4086  };
4087
4088  /**
4089   * @param  {Timeline} timeline
4090   * @param  {TimelinePosition} [timePosition]
4091   * @return {Number}
4092   */
4093  const parseTimelinePosition = (timeline, timePosition) => {
4094    let tlDuration = timeline.iterationDuration;
4095    if (tlDuration === minValue) tlDuration = 0;
4096    if (isUnd(timePosition)) return tlDuration;
4097    if (isNum(+timePosition)) return +timePosition;
4098    const timePosStr = /** @type {String} */(timePosition);
4099    const tlLabels = timeline ? timeline.labels : null;
4100    const hasLabels = !isNil(tlLabels);
4101    const prevOffset = getPrevChildOffset(timeline, timePosStr);
4102    const hasSibling = !isUnd(prevOffset);
4103    const matchedRelativeOperator = relativeValuesExecRgx.exec(timePosStr);
4104    if (matchedRelativeOperator) {
4105      const fullOperator = matchedRelativeOperator[0];
4106      const split = timePosStr.split(fullOperator);
4107      const labelOffset = hasLabels && split[0] ? tlLabels[split[0]] : tlDuration;
4108      const parsedOffset = hasSibling ? prevOffset : hasLabels ? labelOffset : tlDuration;
4109      const parsedNumericalOffset = +split[1];
4110      return getRelativeValue(parsedOffset, parsedNumericalOffset, fullOperator[0]);
4111    } else {
4112      return hasSibling ? prevOffset :
4113             hasLabels ? !isUnd(tlLabels[timePosStr]) ? tlLabels[timePosStr] :
4114             tlDuration : tlDuration;
4115    }
4116  };
4117
4118  
4119
4120  
4121
4122  /**
4123   * @param {Timeline} tl
4124   * @return {Number}
4125   */
4126  function getTimelineTotalDuration(tl) {
4127    return clampInfinity(((tl.iterationDuration + tl._loopDelay) * tl.iterationCount) - tl._loopDelay) || minValue;
4128  }
4129
4130  /**
4131   * @overload
4132   * @param  {TimerParams} childParams
4133   * @param  {Timeline} tl
4134   * @param  {Number} timePosition
4135   * @return {Timeline}
4136   *
4137   * @overload
4138   * @param  {AnimationParams} childParams
4139   * @param  {Timeline} tl
4140   * @param  {Number} timePosition
4141   * @param  {TargetsParam} targets
4142   * @param  {Number} [index]
4143   * @param  {Number} [length]
4144   * @return {Timeline}
4145   *
4146   * @param  {TimerParams|AnimationParams} childParams
4147   * @param  {Timeline} tl
4148   * @param  {Number} timePosition
4149   * @param  {TargetsParam} [targets]
4150   * @param  {Number} [index]
4151   * @param  {Number} [length]
4152   */
4153  function addTlChild(childParams, tl, timePosition, targets, index, length) {
4154    const isSetter = isNum(childParams.duration) && /** @type {Number} */(childParams.duration) <= minValue;
4155    // Offset the tl position with -minValue for 0 duration animations or .set() calls in order to align their end value with the defined position
4156    const adjustedPosition = isSetter ? timePosition - minValue : timePosition;
4157    if (tl.composition) tick(tl, adjustedPosition, 1, 1, tickModes.AUTO);
4158    const tlChild = targets ?
4159      new JSAnimation(targets,/** @type {AnimationParams} */(childParams), tl, adjustedPosition, false, index, length) :
4160      new Timer(/** @type {TimerParams} */(childParams), tl, adjustedPosition);
4161    if (tl.composition) tlChild.init(true);
4162    // TODO: Might be better to insert at a position relative to startTime?
4163    addChild(tl, tlChild);
4164    forEachChildren(tl, (/** @type {Renderable} */child) => {
4165      const childTLOffset = child._offset + child._delay;
4166      const childDur = childTLOffset + child.duration;
4167      if (childDur > tl.iterationDuration) tl.iterationDuration = childDur;
4168    });
4169    tl.duration = getTimelineTotalDuration(tl);
4170    return tl;
4171  }
4172
4173  let TLId = 0;
4174
4175  class Timeline extends Timer {
4176
4177    /**
4178     * @param {TimelineParams} [parameters]
4179     */
4180    constructor(parameters = {}) {
4181      super(/** @type {TimerParams&TimelineParams} */(parameters), null, 0);
4182      ++TLId;
4183      /** @type {String|Number} */
4184      this.id = !isUnd(parameters.id) ? parameters.id : TLId;
4185      /** @type {Number} */
4186      this.duration = 0; // TL duration starts at 0 and grows when adding children
4187      /** @type {Record<String, Number>} */
4188      this.labels = {};
4189      const defaultsParams = parameters.defaults;
4190      const globalDefaults = globals.defaults;
4191      /** @type {DefaultsParams} */
4192      this.defaults = defaultsParams ? mergeObjects(defaultsParams, globalDefaults) : globalDefaults;
4193      /** @type {Boolean} */
4194      this.composition = setValue(parameters.composition, true);
4195      /** @type {Callback<this>} */
4196      this.onRender = parameters.onRender || globalDefaults.onRender;
4197      const tlPlaybackEase = setValue(parameters.playbackEase, globalDefaults.playbackEase);
4198      this._ease = tlPlaybackEase ? parseEase(tlPlaybackEase) : null;
4199      /** @type {Number} */
4200      this.iterationDuration = 0;
4201    }
4202
4203    /**
4204     * @overload
4205     * @param {TargetsParam} a1
4206     * @param {AnimationParams} a2
4207     * @param {TimelinePosition|StaggerFunction<Number|String>} [a3]
4208     * @return {this}
4209     *
4210     * @overload
4211     * @param {TimerParams} a1
4212     * @param {TimelinePosition} [a2]
4213     * @return {this}
4214     *
4215     * @param {TargetsParam|TimerParams} a1
4216     * @param {TimelinePosition|AnimationParams} a2
4217     * @param {TimelinePosition|StaggerFunction<Number|String>} [a3]
4218     */
4219    add(a1, a2, a3) {
4220      const isAnim = isObj(a2);
4221      const isTimer = isObj(a1);
4222      if (isAnim || isTimer) {
4223        this._hasChildren = true;
4224        if (isAnim) {
4225          const childParams = /** @type {AnimationParams} */(a2);
4226          // Check for function for children stagger positions
4227          if (isFnc(a3)) {
4228            const staggeredPosition = a3;
4229            const parsedTargetsArray = parseTargets(/** @type {TargetsParam} */(a1));
4230            // Store initial duration before adding new children that will change the duration
4231            const tlDuration = this.duration;
4232            // Store initial _iterationDuration before adding new children that will change the duration
4233            const tlIterationDuration = this.iterationDuration;
4234            // Store the original id in order to add specific indexes to the new animations ids
4235            const id = childParams.id;
4236            let i = 0;
4237            /** @type {Number} */
4238            const parsedLength = (parsedTargetsArray.length);
4239            parsedTargetsArray.forEach((/** @type {Target} */target) => {
4240              // Create a new parameter object for each staggered children
4241              const staggeredChildParams = { ...childParams };
4242              // Reset the duration of the timeline iteration before each stagger to prevent wrong start value calculation
4243              this.duration = tlDuration;
4244              this.iterationDuration = tlIterationDuration;
4245              if (!isUnd(id)) staggeredChildParams.id = id + '-' + i;
4246              addTlChild(
4247                staggeredChildParams,
4248                this,
4249                parseTimelinePosition(this, staggeredPosition(target, i, parsedLength, this)),
4250                target,
4251                i,
4252                parsedLength
4253              );
4254              i++;
4255            });
4256          } else {
4257            addTlChild(
4258              childParams,
4259              this,
4260              parseTimelinePosition(this, a3),
4261              /** @type {TargetsParam} */(a1),
4262            );
4263          }
4264        } else {
4265          // It's a Timer
4266          addTlChild(
4267            /** @type TimerParams */(a1),
4268            this,
4269            parseTimelinePosition(this,a2),
4270          );
4271        }
4272        if (this.composition) this.init(true);
4273        return this;
4274      }
4275    }
4276
4277    /**
4278     * @overload
4279     * @param {Tickable} [synced]
4280     * @param {TimelinePosition} [position]
4281     * @return {this}
4282     *
4283     * @overload
4284     * @param {globalThis.Animation} [synced]
4285     * @param {TimelinePosition} [position]
4286     * @return {this}
4287     *
4288     * @overload
4289     * @param {WAAPIAnimation} [synced]
4290     * @param {TimelinePosition} [position]
4291     * @return {this}
4292     *
4293     * @param {Tickable|WAAPIAnimation|globalThis.Animation} [synced]
4294     * @param {TimelinePosition} [position]
4295     */
4296    sync(synced, position) {
4297      if (isUnd(synced) || synced && isUnd(synced.pause)) return this;
4298      synced.pause();
4299      const duration = +(/** @type {globalThis.Animation} */(synced).effect ? /** @type {globalThis.Animation} */(synced).effect.getTiming().duration : /** @type {Tickable} */(synced).duration);
4300      return this.add(synced, { currentTime: [0, duration], duration, delay: 0, ease: 'linear', playbackEase: 'linear' }, position);
4301    }
4302
4303    /**
4304     * @param  {TargetsParam} targets
4305     * @param  {AnimationParams} parameters
4306     * @param  {TimelinePosition} [position]
4307     * @return {this}
4308     */
4309    set(targets, parameters, position) {
4310      if (isUnd(parameters)) return this;
4311      parameters.duration = minValue;
4312      parameters.composition = compositionTypes.replace;
4313      return this.add(targets, parameters, position);
4314    }
4315
4316    /**
4317     * @param {Callback<Timer>} callback
4318     * @param {TimelinePosition} [position]
4319     * @return {this}
4320     */
4321    call(callback, position) {
vendor: 3,147 bytes, lines 4322-4436
4322      if (isUnd(callback) || callback && !isFnc(callback)) return this;
4323      return this.add({ duration: 0, delay: 0, onComplete: () => callback(this) }, position);
4324    }
4325
4326    /**
4327     * @param {String} labelName
4328     * @param {TimelinePosition} [position]
4329     * @return {this}
4330     *
4331     */
4332    label(labelName, position) {
4333      if (isUnd(labelName) || labelName && !isStr(labelName)) return this;
4334      this.labels[labelName] = parseTimelinePosition(this, position);
4335      return this;
4336    }
4337
4338    /**
4339     * @param  {TargetsParam} targets
4340     * @param  {String} [propertyName]
4341     * @return {this}
4342     */
4343    remove(targets, propertyName) {
4344      removeTargetsFromRenderable(parseTargets(targets), this, propertyName);
4345      return this;
4346    }
4347
4348    /**
4349     * @param  {Number} newDuration
4350     * @return {this}
4351     */
4352    stretch(newDuration) {
4353      const currentDuration = this.duration;
4354      if (currentDuration === normalizeTime(newDuration)) return this;
4355      const timeScale = newDuration / currentDuration;
4356      const labels = this.labels;
4357      forEachChildren(this, (/** @type {JSAnimation} */child) => child.stretch(child.duration * timeScale));
4358      for (let labelName in labels) labels[labelName] *= timeScale;
4359      return super.stretch(newDuration);
4360    }
4361
4362    /**
4363     * @return {this}
4364     */
4365    refresh() {
4366      forEachChildren(this, (/** @type {JSAnimation} */child) => {
4367        if (child.refresh) child.refresh();
4368      });
4369      return this;
4370    }
4371
4372    /**
4373     * @return {this}
4374     */
4375    revert() {
4376      super.revert();
4377      forEachChildren(this, (/** @type {JSAnimation} */child) => child.revert, true);
4378      return cleanInlineStyles(this);
4379    }
4380
4381    /**
4382     * @typedef {this & {then: null}} ResolvedTimeline
4383     */
4384
4385    /**
4386     * @param  {Callback<ResolvedTimeline>} [callback]
4387     * @return Promise<this>
4388     */
4389    then(callback) {
4390      return super.then(callback);
4391    }
4392  }
4393
4394  /**
4395   * @param {TimelineParams} [parameters]
4396   * @return {Timeline}
4397   */
4398  const createTimeline = parameters => new Timeline(parameters).init();
4399
4400  
4401
4402  class Animatable {
4403    /**
4404     * @param {TargetsParam} targets
4405     * @param {AnimatableParams} parameters
4406     */
4407    constructor(targets, parameters) {
4408      if (scope.current) scope.current.register(this);
4409      const beginHandler = () => {
4410        if (this.callbacks.completed) this.callbacks.reset();
4411        this.callbacks.play();
4412      };
4413      const pauseHandler = () => {
4414        if (this.callbacks.completed) return;
4415        let paused = true;
4416        for (let name in this.animations) {
4417          const anim = this.animations[name];
4418          if (!anim.paused && paused) {
4419            paused = false;
4420            break;
4421          }
4422        }
4423        if (paused) {
4424          this.callbacks.complete();
4425        }
4426      };
4427      /** @type {AnimationParams} */
4428      const globalParams = {
4429        onBegin: beginHandler,
4430        onComplete: pauseHandler,
4431        onPause: pauseHandler,
4432      };
4433      /** @type {AnimationParams} */
4434      const callbacksAnimationParams = { v: 1, autoplay: false };
4435      const properties = {};
4436      this.targets = [];
vendor: 59,905 bytes, lines 4436-6047
4436
4437      this.animations = {};
4438      /** @type {JSAnimation|null} */
4439      this.callbacks = null;
4440      if (isUnd(targets) || isUnd(parameters)) return;
4441      for (let propName in parameters) {
4442        const paramValue = parameters[propName];
4443        if (isKey(propName)) {
4444          properties[propName] = paramValue;
4445        } else if (stringStartsWith(propName, 'on')) {
4446          callbacksAnimationParams[propName] = paramValue;
4447        } else {
4448          globalParams[propName] = paramValue;
4449        }
4450      }
4451      this.callbacks = new JSAnimation({ v: 0 }, callbacksAnimationParams);
4452      for (let propName in properties) {
4453        const propValue = properties[propName];
4454        const isObjValue = isObj(propValue);
4455        /** @type {TweenParamsOptions} */
4456        let propParams = {};
4457        let to = '+=0';
4458        if (isObjValue) {
4459          const unit = propValue.unit;
4460          if (isStr(unit)) to += unit;
4461        } else {
4462          propParams.duration = propValue;
4463        }
4464        propParams[propName] = isObjValue ? mergeObjects({ to }, propValue) : to;
4465        const animParams = mergeObjects(globalParams, propParams);
4466        animParams.composition = compositionTypes.replace;
4467        animParams.autoplay = false;
4468        const animation = this.animations[propName] = new JSAnimation(targets, animParams, null, 0, false).init();
4469        if (!this.targets.length) this.targets.push(...animation.targets);
4470        /** @type {AnimatableProperty} */
4471        this[propName] = (to, duration, ease) => {
4472          const tween = /** @type {Tween} */(animation._head);
4473          if (isUnd(to) && tween) {
4474            const numbers = tween._numbers;
4475            if (numbers && numbers.length) {
4476              return numbers;
4477            } else {
4478              return tween._modifier(tween._number);
4479            }
4480          } else {
4481            forEachChildren(animation, (/** @type {Tween} */tween) => {
4482              if (isArr(to)) {
4483                for (let i = 0, l = /** @type {Array} */(to).length; i < l; i++) {
4484                  if (!isUnd(tween._numbers[i])) {
4485                    tween._fromNumbers[i] = /** @type {Number} */(tween._modifier(tween._numbers[i]));
4486                    tween._toNumbers[i] = to[i];
4487                  }
4488                }
4489              } else {
4490                tween._fromNumber = /** @type {Number} */(tween._modifier(tween._number));
4491                tween._toNumber = /** @type {Number} */(to);
4492              }
4493              if (!isUnd(ease)) tween._ease = parseEase(ease);
4494              tween._currentTime = 0;
4495            });
4496            if (!isUnd(duration)) animation.stretch(duration);
4497            animation.reset(true).resume();
4498            return this;
4499          }
4500        };
4501      }
4502    }
4503
4504    revert() {
4505      for (let propName in this.animations) {
4506        this[propName] = noop;
4507        this.animations[propName].revert();
4508      }
4509      this.animations = {};
4510      this.targets.length = 0;
4511      if (this.callbacks) this.callbacks.revert();
4512      return this;
4513    }
4514  }
4515
4516  /**
4517   * @param {TargetsParam} targets
4518   * @param {AnimatableParams} parameters
4519   * @return {AnimatableObject}
4520   */
4521  const createAnimatable = (targets, parameters) => /** @type {AnimatableObject} */ (new Animatable(targets, parameters));
4522
4523  /**
4524   * Rounds a number to fixed decimal places
4525   * @param  {Number|String} v - Value to round
4526   * @param  {Number} decimalLength - Number of decimal places
4527   * @return {String}
4528   */
4529  const roundPad$1 = (v, decimalLength) => (+v).toFixed(decimalLength);
4530
4531  /**
4532   * Pads the start of a value with a string
4533   * @param  {Number} v - Value to pad
4534   * @param  {Number} totalLength - Target length
4535   * @param  {String} padString - String to pad with
4536   * @return {String}
4537   */
4538  const padStart$1 = (v, totalLength, padString) => `${v}`.padStart(totalLength, padString);
4539
4540  /**
4541   * Pads the end of a value with a string
4542   * @param  {Number} v - Value to pad
4543   * @param  {Number} totalLength - Target length
4544   * @param  {String} padString - String to pad with
4545   * @return {String}
4546   */
4547  const padEnd$1 = (v, totalLength, padString) => `${v}`.padEnd(totalLength, padString);
4548
4549  /**
4550   * Wraps a value within a range
4551   * @param  {Number} v - Value to wrap
4552   * @param  {Number} min - Minimum boundary
4553   * @param  {Number} max - Maximum boundary
4554   * @return {Number}
4555   */
4556  const wrap$1 = (v, min, max) => (((v - min) % (max - min) + (max - min)) % (max - min)) + min;
4557
4558  /**
4559   * Maps a value from one range to another
4560   * @param  {Number} value - Input value
4561   * @param  {Number} inLow - Input range minimum
4562   * @param  {Number} inHigh - Input range maximum
4563   * @param  {Number} outLow - Output range minimum
4564   * @param  {Number} outHigh - Output range maximum
4565   * @return {Number}
4566   */
4567  const mapRange$1 = (value, inLow, inHigh, outLow, outHigh) => outLow + ((value - inLow) / (inHigh - inLow)) * (outHigh - outLow);
4568
4569  /**
4570   * Converts degrees to radians
4571   * @param  {Number} degrees - Angle in degrees
4572   * @return {Number}
4573   */
4574  const degToRad$1 = degrees => degrees * Math.PI / 180;
4575
4576  /**
4577   * Converts radians to degrees
4578   * @param  {Number} radians - Angle in radians
4579   * @return {Number}
4580   */
4581  const radToDeg$1 = radians => radians * 180 / Math.PI;
4582
4583  /**
4584   * Frame rate independent damped lerp
4585   * Based on: https://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/
4586   *
4587   * @param  {Number} start - Starting value
4588   * @param  {Number} end - Target value
4589   * @param  {Number} deltaTime - Delta time in ms
4590   * @param  {Number} factor - Interpolation factor in the range [0, 1]
4591   * @return {Number} The interpolated value
4592   */
4593  const damp$1 = (start, end, deltaTime, factor) => {
4594    return !factor ? start : factor === 1 ? end : lerp$1(start, end, 1 - Math.exp(-factor * deltaTime * .1));
4595  };
4596
4597  var numberImports = /*#__PURE__*/Object.freeze({
4598    __proto__: null,
4599    clamp: clamp$1,
4600    damp: damp$1,
4601    degToRad: degToRad$1,
4602    lerp: lerp$1,
4603    mapRange: mapRange$1,
4604    padEnd: padEnd$1,
4605    padStart: padStart$1,
4606    radToDeg: radToDeg$1,
4607    round: round$1,
4608    roundPad: roundPad$1,
4609    snap: snap$1,
4610    wrap: wrap$1
4611  });
4612
4613  
4614
4615  
4616
4617  /*
4618   * Spring easing solver adapted from https://webkit.org/demos/spring/spring.js
4619   * (c) 2016 Webkit - Apple Inc
4620   */
4621
4622  const maxSpringParamValue = K * 10;
4623
4624  class Spring {
4625    /**
4626     * @param {SpringParams} [parameters]
4627     */
4628    constructor(parameters = {}) {
4629      const hasBounceOrDuration = !isUnd(parameters.bounce) || !isUnd(parameters.duration);
4630      this.timeStep = .02; // Interval fed to the solver to calculate duration
4631      this.restThreshold = .0005; // Values below this threshold are considered resting position
4632      this.restDuration = 200; // Duration in ms used to check if the spring is resting after reaching restThreshold
4633      this.maxDuration = 60000; // The maximum allowed spring duration in ms (default 1 min)
4634      this.maxRestSteps = this.restDuration / this.timeStep / K; // How many steps allowed after reaching restThreshold before stopping the duration calculation
4635      this.maxIterations = this.maxDuration / this.timeStep / K; // Calculate the maximum iterations allowed based on maxDuration
4636      this.bn = clamp$1(setValue(parameters.bounce, .5), -1, 1); // The bounce percentage between -1 and 1.
4637      this.pd = clamp$1(setValue(parameters.duration, 628), 10 * globals.timeScale, maxSpringParamValue * globals.timeScale); // The perceived duration
4638      this.m = clamp$1(setValue(parameters.mass, 1), 1, maxSpringParamValue);
4639      this.s = clamp$1(setValue(parameters.stiffness, 100), minValue, maxSpringParamValue);
4640      this.d = clamp$1(setValue(parameters.damping, 10), minValue, maxSpringParamValue);
4641      this.v = clamp$1(setValue(parameters.velocity, 0), -maxSpringParamValue, maxSpringParamValue);
4642      this.w0 = 0;
4643      this.zeta = 0;
4644      this.wd = 0;
4645      this.b = 0;
4646      this.completed = false;
4647      this.solverDuration = 0;
4648      this.settlingDuration = 0;
4649      /** @type {JSAnimation} */
4650      this.parent = null;
4651      /** @type {Callback<JSAnimation>} */
4652      this.onComplete = parameters.onComplete || noop;
4653      if (hasBounceOrDuration) this.calculateSDFromBD();
4654      this.compute();
4655      /** @type {EasingFunction} */
4656      this.ease = t => {
4657        const currentTime = t * this.settlingDuration;
4658        const completed = this.completed;
4659        const perceivedTime = this.pd;
4660        if (currentTime >= perceivedTime && !completed) {
4661          this.completed = true;
4662          this.onComplete(this.parent);
4663        }
4664        if (currentTime < perceivedTime && completed) {
4665          this.completed = false;
4666        }
4667        return t === 0 || t === 1 ? t : this.solve(t * this.solverDuration);
4668      };
4669    }
4670
4671    /** @type {EasingFunction} */
4672    solve(time) {
4673      const { zeta, w0, wd, b } = this;
4674      let t = time;
4675      if (zeta < 1) {
4676        // Underdamped
4677        t = exp(-t * zeta * w0) * (1 * cos(wd * t) + b * sin(wd * t));
4678      } else if (zeta === 1) {
4679        // Critically damped
4680        t = (1 + b * t) * exp(-t * w0);
4681      } else {
4682        // Overdamped
4683        // Using exponential instead of cosh and sinh functions to prevent Infinity
4684        // Original exp(-zeta * w0 * t) * (cosh(wd * t) + b * sinh(wd * t))
4685        t = ((1 + b) * exp((-zeta * w0 + wd) * t) + (1 - b) * exp((-zeta * w0 - wd) * t)) / 2;
4686      }
4687      return 1 - t;
4688    }
4689
4690    calculateSDFromBD() {
4691      // Apple's SwiftUI perceived spring duration implementation https://developer.apple.com/videos/play/wwdc2023/10158/?time=1010
4692      // Equations taken from Kevin Grajeda's article https://www.kvin.me/posts/effortless-ui-spring-animations
4693      const pds = globals.timeScale === 1 ? this.pd / K : this.pd;
4694      // Mass and velocity should be set to their default values
4695      this.m = 1;
4696      this.v = 0;
4697      // Stiffness = (2π ÷ perceptualDuration)²
4698      this.s = pow((2 * PI) / pds, 2);
4699      if (this.bn >= 0) {
4700        // For bounce ≥ 0 (critically damped to underdamped)
4701        // damping = ((1 - bounce) × 4π) ÷ perceptualDuration
4702        this.d = ((1 - this.bn) * 4 * PI) / pds;
4703      } else {
4704        // For bounce < 0 (overdamped)
4705        // damping = 4π ÷ (perceptualDuration × (1 + bounce))
4706        // Note: (1 + bounce) is positive since bounce is negative
4707        this.d = (4 * PI) / (pds * (1 + this.bn));
4708      }
4709      this.s = round$1(clamp$1(this.s, minValue, maxSpringParamValue), 3);
4710      this.d = round$1(clamp$1(this.d, minValue, 300), 3); // Clamping to 300 is needed to prevent insane values in the solver
4711    }
4712
4713    calculateBDFromSD() {
4714      // Calculate perceived duration and bounce from stiffness and damping
4715      // Note: We assumes m = 1 and v = 0 for these calculations
4716      const pds = (2 * PI) / sqrt(this.s);
4717      this.pd = pds * (globals.timeScale === 1 ? K : 1);
4718      const zeta = this.d / (2 * sqrt(this.s));
4719      if (zeta <= 1) {
4720        // Critically damped to underdamped
4721        this.bn = 1 - (this.d * pds) / (4 * PI);
4722      } else {
4723        // Overdamped
4724        this.bn = (4 * PI) / (this.d * pds) - 1;
4725      }
4726      this.bn = round$1(clamp$1(this.bn, -1, 1), 3);
4727      this.pd = round$1(clamp$1(this.pd, 10 * globals.timeScale, maxSpringParamValue * globals.timeScale), 3);
4728    }
4729
4730    compute() {
4731      const { maxRestSteps, maxIterations, restThreshold, timeStep, m, d, s, v } = this;
4732      const w0 = this.w0 = clamp$1(sqrt(s / m), minValue, K);
4733      const bouncedZeta = this.zeta = d / (2 * sqrt(s * m));
4734      // Calculate wd based on damping type
4735      if (bouncedZeta < 1) {
4736        // Underdamped
4737        this.wd = w0 * sqrt(1 - bouncedZeta * bouncedZeta);
4738        this.b = (bouncedZeta * w0 + -v) / this.wd;
4739      } else if (bouncedZeta === 1) {
4740        // Critically damped
4741        this.wd = 0;
4742        this.b = -v + w0;
4743      } else {
4744        // Overdamped
4745        this.wd = w0 * sqrt(bouncedZeta * bouncedZeta - 1);
4746        this.b = (bouncedZeta * w0 + -v) / this.wd;
4747      }
4748
4749      let solverTime = 0;
4750      let restSteps = 0;
4751      let iterations = 0;
4752      while (restSteps <= maxRestSteps && iterations <= maxIterations) {
4753        if (abs(1 - this.solve(solverTime)) < restThreshold) {
4754          restSteps++;
4755        } else {
4756          restSteps = 0;
4757        }
4758        this.solverDuration = solverTime;
4759        solverTime += timeStep;
4760        iterations++;
4761      }
4762      this.settlingDuration = round$1(this.solverDuration * K, 0) * globals.timeScale;
4763    }
4764
4765    get bounce() {
4766      return this.bn;
4767    }
4768
4769    set bounce(v) {
4770      this.bn = clamp$1(setValue(v, 1), -1, 1);
4771      this.calculateSDFromBD();
4772      this.compute();
4773    }
4774
4775    get duration() {
4776      return this.pd;
4777    }
4778
4779    set duration(v) {
4780      this.pd = clamp$1(setValue(v, 1), 10 * globals.timeScale, maxSpringParamValue * globals.timeScale);
4781      this.calculateSDFromBD();
4782      this.compute();
4783    }
4784
4785    get stiffness() {
4786      return this.s;
4787    }
4788
4789    set stiffness(v) {
4790      this.s = clamp$1(setValue(v, 100), minValue, maxSpringParamValue);
4791      this.calculateBDFromSD();
4792      this.compute();
4793    }
4794
4795    get damping() {
4796      return this.d;
4797    }
4798
4799    set damping(v) {
4800      this.d = clamp$1(setValue(v, 10), minValue, maxSpringParamValue);
4801      this.calculateBDFromSD();
4802      this.compute();
4803    }
4804
4805    get mass() {
4806      return this.m;
4807    }
4808
4809    set mass(v) {
4810      this.m = clamp$1(setValue(v, 1), 1, maxSpringParamValue);
4811      this.compute();
4812    }
4813
4814    get velocity() {
4815      return this.v;
4816    }
4817
4818    set velocity(v) {
4819      this.v = clamp$1(setValue(v, 0), -maxSpringParamValue, maxSpringParamValue);
4820      this.compute();
4821    }
4822  }
4823
4824  /**
4825   * @param {SpringParams} [parameters]
4826   * @returns {Spring}
4827   */
4828  const spring = (parameters) => new Spring(parameters);
4829
4830  /**
4831   * @deprecated createSpring() is deprecated use spring() instead
4832   *
4833   * @param {SpringParams} [parameters]
4834   * @returns {Spring}
4835   */
4836  const createSpring = (parameters) => {
4837    console.warn('createSpring() is deprecated use spring() instead');
4838    return new Spring(parameters);
4839  };
4840
4841  
4842
4843  
4844
4845  /**
4846   * @param {Event} e
4847   */
4848  const preventDefault = e => {
4849    if (e.cancelable) e.preventDefault();
4850  };
4851
4852  class DOMProxy {
4853    /** @param {Object} el */
4854    constructor(el) {
4855      this.el = el;
4856      this.zIndex = 0;
4857      this.parentElement = null;
4858      this.classList = {
4859        add: noop,
4860        remove: noop,
4861      };
4862    }
4863
4864    get x() { return this.el.x || 0 };
4865    set x(v) { this.el.x = v; };
4866
4867    get y() { return this.el.y || 0 };
4868    set y(v) { this.el.y = v; };
4869
4870    get width() { return this.el.width || 0 };
4871    set width(v) { this.el.width = v; };
4872
4873    get height() { return this.el.height || 0 };
4874    set height(v) { this.el.height = v; };
4875
4876    getBoundingClientRect() {
4877      return {
4878        top: this.y,
4879        right: this.x,
4880        bottom: this.y + this.height,
4881        left: this.x + this.width,
4882      }
4883    }
4884  }
4885
4886  class Transforms {
4887    /**
4888     * @param {DOMTarget|DOMProxy} $el
4889     */
4890    constructor($el) {
4891      this.$el = $el;
4892      this.inlineTransforms = [];
4893      this.point = new DOMPoint();
4894      this.inversedMatrix = this.getMatrix().inverse();
4895    }
4896
4897    /**
4898     * @param {Number} x
4899     * @param {Number} y
4900     * @return {DOMPoint}
4901     */
4902    normalizePoint(x, y) {
4903      this.point.x = x;
4904      this.point.y = y;
4905      return this.point.matrixTransform(this.inversedMatrix);
4906    }
4907
4908    /**
4909     * @callback TraverseParentsCallback
4910     * @param {DOMTarget} $el
4911     * @param {Number} i
4912     */
4913
4914    /**
4915     * @param {TraverseParentsCallback} cb
4916     */
4917    traverseUp(cb) {
4918      let $el = /** @type {DOMTarget|Document} */(this.$el.parentElement), i = 0;
4919      while ($el && $el !== doc) {
4920        cb(/** @type {DOMTarget} */($el), i);
4921        $el = /** @type {DOMTarget} */($el.parentElement);
4922        i++;
4923      }
4924    }
4925
4926    getMatrix() {
4927      const matrix = new DOMMatrix();
4928      this.traverseUp($el => {
4929        const transformValue = getComputedStyle($el).transform;
4930        if (transformValue) {
4931          const elMatrix = new DOMMatrix(transformValue);
4932          matrix.preMultiplySelf(elMatrix);
4933        }
4934      });
4935      return matrix;
4936    }
4937
4938    remove() {
4939      this.traverseUp(($el, i) => {
4940        this.inlineTransforms[i] = $el.style.transform;
4941        $el.style.transform = 'none';
4942      });
4943    }
4944
4945    revert() {
4946      this.traverseUp(($el, i) => {
4947        const ct = this.inlineTransforms[i];
4948        if (ct === '') {
4949          $el.style.removeProperty('transform');
4950        } else {
4951          $el.style.transform = ct;
4952        }
4953      });
4954    }
4955  }
4956
4957  /**
4958   * @template {Array<Number>|DOMTargetSelector|String|Number|Boolean|Function|DraggableCursorParams|DraggableDragThresholdParams} T
4959   * @param {T | ((draggable: Draggable) => T)} value
4960   * @param {Draggable} draggable
4961   * @return {T}
4962   */
4963  const parseDraggableFunctionParameter = (value, draggable) => value && isFnc(value) ? /** @type {Function} */(value)(draggable) : /** @type {T} */(value);
4964
4965  let zIndex = 0;
4966
4967  class Draggable {
4968    /**
4969     * @param {TargetsParam} target
4970     * @param {DraggableParams} [parameters]
4971     */
4972    constructor(target, parameters = {}) {
4973      if (!target) return;
4974      if (scope.current) scope.current.register(this);
4975      const paramX = parameters.x;
4976      const paramY = parameters.y;
4977      const trigger = parameters.trigger;
4978      const modifier = parameters.modifier;
4979      const ease = parameters.releaseEase;
4980      const customEase = ease && parseEase(ease);
4981      const hasSpring = !isUnd(ease) && !isUnd(/** @type {Spring} */(ease).ease);
4982      const xProp = /** @type {String} */(isObj(paramX) && !isUnd(/** @type {Object} */(paramX).mapTo) ? /** @type {Object} */(paramX).mapTo : 'translateX');
4983      const yProp = /** @type {String} */(isObj(paramY) && !isUnd(/** @type {Object} */(paramY).mapTo) ? /** @type {Object} */(paramY).mapTo : 'translateY');
4984      const container = parseDraggableFunctionParameter(parameters.container, this);
4985      this.containerArray = isArr(container) ? container : null;
4986      this.$container = /** @type {HTMLElement} */(container && !this.containerArray ? parseTargets(/** @type {DOMTarget} */(container))[0] : doc.body);
4987      this.useWin = this.$container === doc.body;
4988      /** @type {Window | HTMLElement} */
4989      this.$scrollContainer = this.useWin ? win : this.$container;
4990      this.$target = /** @type {HTMLElement} */(isObj(target) ? new DOMProxy(target) : parseTargets(target)[0]);
4991      this.$trigger = /** @type {HTMLElement} */(parseTargets(trigger ? trigger : target)[0]);
4992      this.fixed = get(this.$target, 'position') === 'fixed';
4993      // Refreshable parameters
4994      this.isFinePointer = true;
4995      /** @type {[Number, Number, Number, Number]} */
4996      this.containerPadding = [0, 0, 0, 0];
4997      /** @type {Number} */
4998      this.containerFriction = 0;
4999      /** @type {Number} */
5000      this.releaseContainerFriction = 0;
5001      /** @type {Number|Array<Number>} */
5002      this.snapX = 0;
5003      /** @type {Number|Array<Number>} */
5004      this.snapY = 0;
5005      /** @type {Number} */
5006      this.scrollSpeed = 0;
5007      /** @type {Number} */
5008      this.scrollThreshold = 0;
5009      /** @type {Number} */
5010      this.dragSpeed = 0;
5011      /** @type {Number} */
5012      this.dragThreshold = 3;
5013      /** @type {Number} */
5014      this.maxVelocity = 0;
5015      /** @type {Number} */
5016      this.minVelocity = 0;
5017      /** @type {Number} */
5018      this.velocityMultiplier = 0;
5019      /** @type {Boolean|DraggableCursorParams} */
5020      this.cursor = false;
5021      /** @type {Spring} */
5022      this.releaseXSpring = hasSpring ? /** @type {Spring} */(ease) : spring({
5023        mass: setValue(parameters.releaseMass, 1),
5024        stiffness: setValue(parameters.releaseStiffness, 80),
5025        damping: setValue(parameters.releaseDamping, 20),
5026      });
5027      /** @type {Spring} */
5028      this.releaseYSpring = hasSpring ? /** @type {Spring} */(ease) : spring({
5029        mass: setValue(parameters.releaseMass, 1),
5030        stiffness: setValue(parameters.releaseStiffness, 80),
5031        damping: setValue(parameters.releaseDamping, 20),
5032      });
5033      /** @type {EasingFunction} */
5034      this.releaseEase = customEase || eases.outQuint;
5035      /** @type {Boolean} */
5036      this.hasReleaseSpring = hasSpring;
5037      /** @type {Callback<this>} */
5038      this.onGrab = parameters.onGrab || noop;
5039      /** @type {Callback<this>} */
5040      this.onDrag = parameters.onDrag || noop;
5041      /** @type {Callback<this>} */
5042      this.onRelease = parameters.onRelease || noop;
5043      /** @type {Callback<this>} */
5044      this.onUpdate = parameters.onUpdate || noop;
5045      /** @type {Callback<this>} */
5046      this.onSettle = parameters.onSettle || noop;
5047      /** @type {Callback<this>} */
5048      this.onSnap = parameters.onSnap || noop;
5049      /** @type {Callback<this>} */
5050      this.onResize = parameters.onResize || noop;
5051      /** @type {Callback<this>} */
5052      this.onAfterResize = parameters.onAfterResize || noop;
5053      /** @type {[Number, Number]} */
5054      this.disabled = [0, 0];
5055      /** @type {AnimatableParams} */
5056      const animatableParams = {};
5057      if (modifier) animatableParams.modifier = modifier;
5058      if (isUnd(paramX) || paramX === true) {
5059        animatableParams[xProp] = 0;
5060      } else if (isObj(paramX)) {
5061        const paramXObject = /** @type {DraggableAxisParam} */(paramX);
5062        const animatableXParams = {};
5063        if (paramXObject.modifier) animatableXParams.modifier = paramXObject.modifier;
5064        if (paramXObject.composition) animatableXParams.composition = paramXObject.composition;
5065        animatableParams[xProp] = animatableXParams;
5066      } else if (paramX === false) {
5067        animatableParams[xProp] = 0;
5068        this.disabled[0] = 1;
5069      }
5070      if (isUnd(paramY) || paramY === true) {
5071        animatableParams[yProp] = 0;
5072      } else if (isObj(paramY)) {
5073        const paramYObject = /** @type {DraggableAxisParam} */(paramY);
5074        const animatableYParams = {};
5075        if (paramYObject.modifier) animatableYParams.modifier = paramYObject.modifier;
5076        if (paramYObject.composition) animatableYParams.composition = paramYObject.composition;
5077        animatableParams[yProp] = animatableYParams;
5078      } else if (paramY === false) {
5079        animatableParams[yProp] = 0;
5080        this.disabled[1] = 1;
5081      }
5082      /** @type {AnimatableObject} */
5083      this.animate = /** @type {AnimatableObject} */(new Animatable(this.$target, animatableParams));
5084      // Internal props
5085      this.xProp = xProp;
5086      this.yProp = yProp;
5087      this.destX = 0;
5088      this.destY = 0;
5089      this.deltaX = 0;
5090      this.deltaY = 0;
5091      this.scroll = {x: 0, y: 0};
5092      /** @type {[Number, Number, Number, Number]} */
5093      this.coords = [this.x, this.y, 0, 0]; // x, y, temp x, temp y
5094      /** @type {[Number, Number]} */
5095      this.snapped = [0, 0]; // x, y
5096      /** @type {[Number, Number, Number, Number, Number, Number, Number, Number]} */
5097      this.pointer = [0, 0, 0, 0, 0, 0, 0, 0]; // x1, y1, x2, y2, temp x1, temp y1, temp x2, temp y2
5098      /** @type {[Number, Number]} */
5099      this.scrollView = [0, 0]; // w, h
5100      /** @type {[Number, Number, Number, Number]} */
5101      this.dragArea = [0, 0, 0, 0]; // x, y, w, h
5102      /** @type {[Number, Number, Number, Number]} */
5103      this.containerBounds = [-maxValue, maxValue, maxValue, -maxValue]; // t, r, b, l
5104      /** @type {[Number, Number, Number, Number]} */
5105      this.scrollBounds = [0, 0, 0, 0]; // t, r, b, l
5106      /** @type {[Number, Number, Number, Number]} */
5107      this.targetBounds = [0, 0, 0, 0]; // t, r, b, l
5108      /** @type {[Number, Number]} */
5109      this.window = [0, 0]; // w, h
5110      /** @type {[Number, Number, Number]} */
5111      this.velocityStack = [0, 0, 0];
5112      /** @type {Number} */
5113      this.velocityStackIndex = 0;
5114      /** @type {Number} */
5115      this.velocityTime = now();
5116      /** @type {Number} */
5117      this.velocity = 0;
5118      /** @type {Number} */
5119      this.angle = 0;
5120      /** @type {JSAnimation} */
5121      this.cursorStyles = null;
5122      /** @type {JSAnimation} */
5123      this.triggerStyles = null;
5124      /** @type {JSAnimation} */
5125      this.bodyStyles = null;
5126      /** @type {JSAnimation} */
5127      this.targetStyles = null;
5128      /** @type {JSAnimation} */
5129      this.touchActionStyles = null;
5130      this.transforms = new Transforms(this.$target);
5131      this.overshootCoords = { x: 0, y: 0 };
5132      this.overshootTicker = new Timer({
5133        autoplay: false,
5134        onUpdate: () => {
5135          this.updated = true;
5136          this.manual = true;
5137          // Use a duration of 1 to prevent the animatable from completing immediately to prevent issues with onSettle()
5138          // https://github.com/juliangarnier/anime/issues/1045
5139          if (!this.disabled[0]) this.animate[this.xProp](this.overshootCoords.x, 1);
5140          if (!this.disabled[1]) this.animate[this.yProp](this.overshootCoords.y, 1);
5141        },
5142        onComplete: () => {
5143          this.manual = false;
5144          if (!this.disabled[0]) this.animate[this.xProp](this.overshootCoords.x, 0);
5145          if (!this.disabled[1]) this.animate[this.yProp](this.overshootCoords.y, 0);
5146        },
5147      }, null, 0).init();
5148      this.updateTicker = new Timer({ autoplay: false, onUpdate: () => this.update() }, null,0,).init();
5149      this.contained = !isUnd(container);
5150      this.manual = false;
5151      this.grabbed = false;
5152      this.dragged = false;
5153      this.updated = false;
5154      this.released = false;
5155      this.canScroll = false;
5156      this.enabled = false;
5157      this.initialized = false;
5158      this.activeProp = this.disabled[1] ? xProp : yProp;
5159      this.animate.callbacks.onRender = () => {
5160        const hasUpdated = this.updated;
5161        const hasMoved = this.grabbed && hasUpdated;
5162        const hasReleased = !hasMoved && this.released;
5163        const x = this.x;
5164        const y = this.y;
5165        const dx = x - this.coords[2];
5166        const dy = y - this.coords[3];
5167        this.deltaX = dx;
5168        this.deltaY = dy;
5169        this.coords[2] = x;
5170        this.coords[3] = y;
5171        // Check if dx or dy are not 0 to check if the draggable has actually moved
5172        // https://github.com/juliangarnier/anime/issues/1032
5173        if (hasUpdated && (dx || dy)) {
5174          this.onUpdate(this);
5175        }
5176        if (!hasReleased) {
5177          this.updated = false;
5178        } else {
5179          this.computeVelocity(dx, dy);
5180          this.angle = atan2(dy, dx);
5181        }
5182      };
5183      this.animate.callbacks.onComplete = () => {
5184        if ((!this.grabbed && this.released)) {
5185          // Set released to false before calling onSettle to avoid recursion
5186          this.released = false;
5187        }
5188        if (!this.manual) {
5189          this.deltaX = 0;
5190          this.deltaY = 0;
5191          this.velocity = 0;
5192          this.velocityStack[0] = 0;
5193          this.velocityStack[1] = 0;
5194          this.velocityStack[2] = 0;
5195          this.velocityStackIndex = 0;
5196          this.onSettle(this);
5197        }
5198      };
5199      this.resizeTicker = new Timer({
5200        autoplay: false,
5201        duration: 150 * globals.timeScale,
5202        onComplete: () => {
5203          this.onResize(this);
5204          this.refresh();
5205          this.onAfterResize(this);
5206        },
5207      }).init();
5208      this.parameters = parameters;
5209      this.resizeObserver = new ResizeObserver(() => {
5210        if (this.initialized) {
5211          this.resizeTicker.restart();
5212        } else {
5213          this.initialized = true;
5214        }
5215      });
5216      this.enable();
5217      this.refresh();
5218      this.resizeObserver.observe(this.$container);
5219      if (!isObj(target)) this.resizeObserver.observe(this.$target);
5220    }
5221
5222    /**
5223     * @param  {Number} dx
5224     * @param  {Number} dy
5225     * @return {Number}
5226     */
5227    computeVelocity(dx, dy) {
5228      const prevTime = this.velocityTime;
5229      const curTime = now();
5230      const elapsed = curTime - prevTime;
5231      if (elapsed < 17) return this.velocity;
5232      this.velocityTime = curTime;
5233      const velocityStack = this.velocityStack;
5234      const vMul = this.velocityMultiplier;
5235      const minV = this.minVelocity;
5236      const maxV = this.maxVelocity;
5237      const vi = this.velocityStackIndex;
5238      velocityStack[vi] = round$1(clamp$1((sqrt(dx * dx + dy * dy) / elapsed) * vMul, minV, maxV), 5);
5239      const velocity = max(velocityStack[0], velocityStack[1], velocityStack[2]);
5240      this.velocity = velocity;
5241      this.velocityStackIndex = (vi + 1) % 3;
5242      return velocity;
5243    }
5244
5245    /**
5246     * @param {Number}  x
5247     * @param {Boolean} [muteUpdateCallback]
5248     * @return {this}
5249     */
5250    setX(x, muteUpdateCallback = false) {
5251      if (this.disabled[0]) return;
5252      const v = round$1(x, 5);
5253      this.overshootTicker.pause();
5254      this.manual = true;
5255      this.updated = !muteUpdateCallback;
5256      this.destX = v;
5257      this.snapped[0] = snap$1(v, this.snapX);
5258      this.animate[this.xProp](v, 0);
5259      this.manual = false;
5260      return this;
5261    }
5262
5263    /**
5264     * @param {Number}  y
5265     * @param {Boolean} [muteUpdateCallback]
5266     * @return {this}
5267     */
5268    setY(y, muteUpdateCallback = false) {
5269      if (this.disabled[1]) return;
5270      const v = round$1(y, 5);
5271      this.overshootTicker.pause();
5272      this.manual = true;
5273      this.updated = !muteUpdateCallback;
5274      this.destY = v;
5275      this.snapped[1] = snap$1(v, this.snapY);
5276      this.animate[this.yProp](v, 0);
5277      this.manual = false;
5278      return this;
5279    }
5280
5281    get x() {
5282      return round$1(/** @type {Number} */(this.animate[this.xProp]()), globals.precision);
5283    }
5284
5285    set x(x) {
5286      this.setX(x, false);
5287    }
5288
5289    get y() {
5290      return round$1(/** @type {Number} */(this.animate[this.yProp]()), globals.precision);
5291    }
5292
5293    set y(y) {
5294      this.setY(y, false);
5295    }
5296
5297    get progressX() {
5298      return mapRange$1(this.x, this.containerBounds[3], this.containerBounds[1], 0, 1);
5299    }
5300
5301    set progressX(x) {
5302      this.setX(mapRange$1(x, 0, 1, this.containerBounds[3], this.containerBounds[1]), false);
5303    }
5304
5305    get progressY() {
5306      return mapRange$1(this.y, this.containerBounds[0], this.containerBounds[2], 0, 1);
5307    }
5308
5309    set progressY(y) {
5310      this.setY(mapRange$1(y, 0, 1, this.containerBounds[0], this.containerBounds[2]), false);
5311    }
5312
5313    updateScrollCoords() {
5314      const sx = round$1(this.useWin ? win.scrollX : this.$container.scrollLeft, 0);
5315      const sy = round$1(this.useWin ? win.scrollY : this.$container.scrollTop, 0);
5316      const [ cpt, cpr, cpb, cpl ] = this.containerPadding;
5317      const threshold = this.scrollThreshold;
5318      this.scroll.x = sx;
5319      this.scroll.y = sy;
5320      this.scrollBounds[0] = sy - this.targetBounds[0] + cpt - threshold;
5321      this.scrollBounds[1] = sx - this.targetBounds[1] - cpr + threshold;
5322      this.scrollBounds[2] = sy - this.targetBounds[2] - cpb + threshold;
5323      this.scrollBounds[3] = sx - this.targetBounds[3] + cpl - threshold;
5324    }
5325
5326    updateBoundingValues() {
5327      const $container = this.$container;
5328      // Return early if no $container defined to prevents error when reading scrollWidth / scrollHeight
5329      // https://github.com/juliangarnier/anime/issues/1064
5330      if (!$container) return;
5331      const cx = this.x;
5332      const cy = this.y;
5333      const cx2 = this.coords[2];
5334      const cy2 =  this.coords[3];
5335      // Prevents interfering with the scroll area in cases the target is outside of the container
5336      // Make sure the temp coords are also adjuset to prevents wrong delta calculation on updates
5337      this.coords[2] = 0;
5338      this.coords[3] = 0;
5339      this.setX(0, true);
5340      this.setY(0, true);
5341      this.transforms.remove();
5342      const iw = this.window[0] = win.innerWidth;
5343      const ih = this.window[1] = win.innerHeight;
5344      const uw = this.useWin;
5345      const sw = $container.scrollWidth;
5346      const sh = $container.scrollHeight;
5347      const fx = this.fixed;
5348      const transformContainerRect = $container.getBoundingClientRect();
5349      const [ cpt, cpr, cpb, cpl ] = this.containerPadding;
5350      this.dragArea[0] = uw ? 0 : transformContainerRect.left;
5351      this.dragArea[1] = uw ? 0 : transformContainerRect.top;
5352      this.scrollView[0] = uw ? clamp$1(sw, iw, sw) : sw;
5353      this.scrollView[1] = uw ? clamp$1(sh, ih, sh) : sh;
5354      this.updateScrollCoords();
5355      const { width, height, left, top, right, bottom } = $container.getBoundingClientRect();
5356      this.dragArea[2] = round$1(uw ? clamp$1(width, iw, iw) : width, 0);
5357      this.dragArea[3] = round$1(uw ? clamp$1(height, ih, ih) : height, 0);
5358      const containerOverflow = get($container, 'overflow');
5359      const visibleOverflow = containerOverflow === 'visible';
5360      const hiddenOverflow = containerOverflow === 'hidden';
5361      this.canScroll = fx ? false :
5362        this.contained &&
5363        (($container === doc.body && visibleOverflow) || (!hiddenOverflow && !visibleOverflow)) &&
5364        (sw > this.dragArea[2] + cpl - cpr || sh > this.dragArea[3] + cpt - cpb) &&
5365        (!this.containerArray || (this.containerArray && !isArr(this.containerArray)));
5366      if (this.contained) {
5367        const sx = this.scroll.x;
5368        const sy = this.scroll.y;
5369        const canScroll = this.canScroll;
5370        const targetRect = this.$target.getBoundingClientRect();
5371        const hiddenLeft = canScroll ? uw ? 0 : $container.scrollLeft : 0;
5372        const hiddenTop = canScroll ? uw ? 0 : $container.scrollTop : 0;
5373        const hiddenRight = canScroll ? this.scrollView[0] - hiddenLeft - width : 0;
5374        const hiddenBottom = canScroll ? this.scrollView[1] - hiddenTop - height : 0;
5375        this.targetBounds[0] = round$1((targetRect.top + sy) - (uw ? 0 : top), 0);
5376        this.targetBounds[1] = round$1((targetRect.right + sx) - (uw ? iw : right), 0);
5377        this.targetBounds[2] = round$1((targetRect.bottom + sy) - (uw ? ih : bottom), 0);
5378        this.targetBounds[3] = round$1((targetRect.left + sx) - (uw ? 0 : left), 0);
5379        if (this.containerArray) {
5380          this.containerBounds[0] = this.containerArray[0] + cpt;
5381          this.containerBounds[1] = this.containerArray[1] - cpr;
5382          this.containerBounds[2] = this.containerArray[2] - cpb;
5383          this.containerBounds[3] = this.containerArray[3] + cpl;
5384        } else {
5385          this.containerBounds[0] = -round$1(targetRect.top - (fx ? clamp$1(top, 0, ih) : top) + hiddenTop - cpt, 0);
5386          this.containerBounds[1] = -round$1(targetRect.right - (fx ? clamp$1(right, 0, iw) : right) - hiddenRight + cpr, 0);
5387          this.containerBounds[2] = -round$1(targetRect.bottom - (fx ? clamp$1(bottom, 0, ih) : bottom) - hiddenBottom + cpb, 0);
5388          this.containerBounds[3] = -round$1(targetRect.left - (fx ? clamp$1(left, 0, iw) : left) + hiddenLeft - cpl, 0);
5389        }
5390      }
5391      this.transforms.revert();
5392      // Restore coordinates
5393      this.coords[2] = cx2;
5394      this.coords[3] = cy2;
5395      this.setX(cx, true);
5396      this.setY(cy, true);
5397    }
5398
5399    /**
5400     * @param  {Array} bounds
5401     * @param  {Number} x
5402     * @param  {Number} y
5403     * @return {Number}
5404     */
5405    isOutOfBounds(bounds, x, y) {
5406      // Returns 0 if not OB, 1 if x is OB, 2 if y is OB, 3 if both x and y are OB
5407      if (!this.contained) return 0;
5408      const [ bt, br, bb, bl ] = bounds;
5409      const [ dx, dy ] = this.disabled;
5410      const obx = !dx && x < bl || !dx && x > br;
5411      const oby = !dy && y < bt || !dy && y > bb;
5412      return obx && !oby ? 1 : !obx && oby ? 2 : obx && oby ? 3 : 0;
5413    }
5414
5415    refresh() {
5416      const params = this.parameters;
5417      const paramX = params.x;
5418      const paramY = params.y;
5419      const container = parseDraggableFunctionParameter(params.container, this);
5420      const cp = parseDraggableFunctionParameter(params.containerPadding, this) || 0;
5421      const containerPadding = /** @type {[Number, Number, Number, Number]} */(isArr(cp) ? cp : [cp, cp, cp, cp]);
5422      const cx = this.x;
5423      const cy = this.y;
5424      const parsedCursorStyles = parseDraggableFunctionParameter(params.cursor, this);
5425      const cursorStyles = { onHover: 'grab', onGrab: 'grabbing' };
5426      if (parsedCursorStyles) {
5427        const { onHover, onGrab } = /** @type {DraggableCursorParams} */(parsedCursorStyles);
5428        if (onHover) cursorStyles.onHover = onHover;
5429        if (onGrab) cursorStyles.onGrab = onGrab;
5430      }
5431      const parsedDragThreshold = parseDraggableFunctionParameter(params.dragThreshold, this);
5432      const dragThreshold = { mouse: 3, touch: 7 };
5433      if (isNum(parsedDragThreshold)) {
5434        dragThreshold.mouse = parsedDragThreshold;
5435        dragThreshold.touch = parsedDragThreshold;
5436      } else if (parsedDragThreshold) {
5437        const { mouse, touch } = parsedDragThreshold;
5438        if (!isUnd(mouse)) dragThreshold.mouse = mouse;
5439        if (!isUnd(touch)) dragThreshold.touch = touch;
5440      }
5441      this.containerArray = isArr(container) ? container : null;
5442      this.$container = /** @type {HTMLElement} */(container && !this.containerArray ? parseTargets(/** @type {DOMTarget} */(container))[0] : doc.body);
5443      this.useWin = this.$container === doc.body;
5444      /** @type {Window | HTMLElement} */
5445      this.$scrollContainer = this.useWin ? win : this.$container;
5446      this.isFinePointer = matchMedia('(pointer:fine)').matches;
5447      this.containerPadding = setValue(containerPadding, [0, 0, 0, 0]);
5448      this.containerFriction = clamp$1(setValue(parseDraggableFunctionParameter(params.containerFriction, this), .8), 0, 1);
5449      this.releaseContainerFriction = clamp$1(setValue(parseDraggableFunctionParameter(params.releaseContainerFriction, this), this.containerFriction), 0, 1);
5450      this.snapX = parseDraggableFunctionParameter(isObj(paramX) && !isUnd(paramX.snap) ? paramX.snap : params.snap, this);
5451      this.snapY = parseDraggableFunctionParameter(isObj(paramY) && !isUnd(paramY.snap) ? paramY.snap : params.snap, this);
5452      this.scrollSpeed = setValue(parseDraggableFunctionParameter(params.scrollSpeed, this), 1.5);
5453      this.scrollThreshold = setValue(parseDraggableFunctionParameter(params.scrollThreshold, this), 20);
5454      this.dragSpeed = setValue(parseDraggableFunctionParameter(params.dragSpeed, this), 1);
5455      this.dragThreshold = this.isFinePointer ? dragThreshold.mouse : dragThreshold.touch;
5456      this.minVelocity = setValue(parseDraggableFunctionParameter(params.minVelocity, this), 0);
5457      this.maxVelocity = setValue(parseDraggableFunctionParameter(params.maxVelocity, this), 50);
5458      this.velocityMultiplier = setValue(parseDraggableFunctionParameter(params.velocityMultiplier, this), 1);
5459      this.cursor = parsedCursorStyles === false ? false : cursorStyles;
5460      this.updateBoundingValues();
5461
5462      // const ob = this.isOutOfBounds(this.containerBounds, this.x, this.y);
5463      // if (ob === 1 || ob === 3) this.progressX = px;
5464      // if (ob === 2 || ob === 3) this.progressY = py;
5465
5466      // if (this.initialized && this.contained) {
5467      //   if (this.progressX !== px) this.progressX = px;
5468      //   if (this.progressY !== py) this.progressY = py;
5469      // }
5470
5471      const [ bt, br, bb, bl ] = this.containerBounds;
5472      this.setX(clamp$1(cx, bl, br), true);
5473      this.setY(clamp$1(cy, bt, bb), true);
5474    }
5475
5476    update() {
5477      this.updateScrollCoords();
5478      if (this.canScroll) {
5479        const [ cpt, cpr, cpb, cpl ] = this.containerPadding;
5480        const [ sw, sh ] = this.scrollView;
5481        const daw = this.dragArea[2];
5482        const dah = this.dragArea[3];
5483        const csx = this.scroll.x;
5484        const csy = this.scroll.y;
5485        const nsw = this.$container.scrollWidth;
5486        const nsh = this.$container.scrollHeight;
5487        const csw = this.useWin ? clamp$1(nsw, this.window[0], nsw) : nsw;
5488        const csh = this.useWin ? clamp$1(nsh, this.window[1], nsh) : nsh;
5489        const swd = sw - csw;
5490        const shd = sh - csh;
5491        // Handle cases where the scrollarea dimensions changes during drag
5492        if (this.dragged && swd > 0) {
5493          this.coords[0] -= swd;
5494          this.scrollView[0] = csw;
5495        }
5496        if (this.dragged && shd > 0) {
5497          this.coords[1] -= shd;
5498          this.scrollView[1] = csh;
5499        }
5500        // Handle autoscroll when target is at the edges of the scroll bounds
5501        const s = this.scrollSpeed * 10;
5502        const threshold = this.scrollThreshold;
5503        const [ x, y ] = this.coords;
5504        const [ st, sr, sb, sl ] = this.scrollBounds;
5505        const t = round$1(clamp$1((y - st + cpt) / threshold, -1, 0) * s, 0);
5506        const r = round$1(clamp$1((x - sr - cpr) / threshold, 0, 1) * s, 0);
5507        const b = round$1(clamp$1((y - sb - cpb) / threshold, 0, 1) * s, 0);
5508        const l = round$1(clamp$1((x - sl + cpl) / threshold, -1, 0) * s, 0);
5509        if (t || b || l || r) {
5510          const [nx, ny] = this.disabled;
5511          let scrollX = csx;
5512          let scrollY = csy;
5513          if (!nx) {
5514            scrollX = round$1(clamp$1(csx + (l || r), 0, sw - daw), 0);
5515            this.coords[0] -= csx - scrollX;
5516          }
5517          if (!ny) {
5518            scrollY = round$1(clamp$1(csy + (t || b), 0, sh - dah), 0);
5519            this.coords[1] -= csy - scrollY;
5520          }
5521          // Note: Safari mobile requires to use different scroll methods depending if using the window or not
5522          if (this.useWin) {
5523            this.$scrollContainer.scrollBy(-(csx - scrollX), -(csy - scrollY));
5524          } else {
5525            this.$scrollContainer.scrollTo(scrollX, scrollY);
5526          }
5527        }
5528      }
5529      const [ ct, cr, cb, cl ] = this.containerBounds;
5530      const [ px1, py1, px2, py2, px3, py3 ] = this.pointer;
5531      this.coords[0] += (px1 - px3) * this.dragSpeed;
5532      this.coords[1] += (py1 - py3) * this.dragSpeed;
5533      this.pointer[4] = px1;
5534      this.pointer[5] = py1;
5535      const [ cx, cy ] = this.coords;
5536      const [ sx, sy ] = this.snapped;
5537      const cf = (1 - this.containerFriction) * this.dragSpeed;
5538      this.setX(cx > cr ? cr + (cx - cr) * cf : cx < cl ? cl + (cx - cl) * cf : cx, false);
5539      this.setY(cy > cb ? cb + (cy - cb) * cf : cy < ct ? ct + (cy - ct) * cf : cy, false);
5540      this.computeVelocity(px1 - px3, py1 - py3);
5541      this.angle = atan2(py1 - py2, px1 - px2);
5542      const [ nsx, nsy ] = this.snapped;
5543      if (nsx !== sx && this.snapX || nsy !== sy && this.snapY) {
5544        this.onSnap(this);
5545      }
5546    }
5547
5548    stop() {
5549      this.updateTicker.pause();
5550      this.overshootTicker.pause();
5551      // Pauses the in bounds onRelease animations
5552      for (let prop in this.animate.animations) this.animate.animations[prop].pause();
5553      removeTargetsFromRenderable([this], null, 'x');
5554      removeTargetsFromRenderable([this], null, 'y');
5555      removeTargetsFromRenderable([this], null, 'progressX');
5556      removeTargetsFromRenderable([this], null, 'progressY');
5557      removeTargetsFromRenderable([this.scroll]); // Removes any active animations on the container scroll
5558      removeTargetsFromRenderable([this.overshootCoords]); // Removes active overshoot animations
5559      return this;
5560    }
5561
5562    /**
5563     * @param {Number} [duration]
5564     * @param {Number} [gap]
5565     * @param {EasingParam} [ease]
5566     * @return {this}
5567     */
5568    scrollInView(duration, gap = 0, ease = eases.inOutQuad) {
5569      this.updateScrollCoords();
5570      const x = this.destX;
5571      const y = this.destY;
5572      const scroll = this.scroll;
5573      const scrollBounds = this.scrollBounds;
5574      const canScroll = this.canScroll;
5575      if (!this.containerArray && this.isOutOfBounds(scrollBounds, x, y)) {
5576        const [ st, sr, sb, sl ] = scrollBounds;
5577        const t = round$1(clamp$1(y - st, -maxValue, 0), 0);
5578        const r = round$1(clamp$1(x - sr, 0, maxValue), 0);
5579        const b = round$1(clamp$1(y - sb, 0, maxValue), 0);
5580        const l = round$1(clamp$1(x - sl, -maxValue, 0), 0);
5581        new JSAnimation(scroll, {
5582          x: round$1(scroll.x + (l ? l - gap : r ? r + gap : 0), 0),
5583          y: round$1(scroll.y + (t ? t - gap : b ? b + gap : 0), 0),
5584          duration: isUnd(duration) ? 350 * globals.timeScale : duration,
5585          ease,
5586          onUpdate: () => {
5587            this.canScroll = false;
5588            this.$scrollContainer.scrollTo(scroll.x, scroll.y);
5589          }
5590        }).init().then(() => {
5591          this.canScroll = canScroll;
5592        });
5593      }
5594      return this;
5595    }
5596
5597    handleHover() {
5598      if (this.isFinePointer && this.cursor && !this.cursorStyles) {
5599        this.cursorStyles = set(this.$trigger, {
5600          cursor: /** @type {DraggableCursorParams} */(this.cursor).onHover
5601        });
5602      }
5603    }
5604
5605    /**
5606     * @param  {Number} [duration]
5607     * @param  {Number} [gap]
5608     * @param  {EasingParam} [ease]
5609     * @return {this}
5610     */
5611    animateInView(duration, gap = 0, ease = eases.inOutQuad) {
5612      this.stop();
5613      this.updateBoundingValues();
5614      const x = this.x;
5615      const y = this.y;
5616      const [ cpt, cpr, cpb, cpl ] = this.containerPadding;
5617      const bt = this.scroll.y - this.targetBounds[0] + cpt + gap;
5618      const br = this.scroll.x - this.targetBounds[1] - cpr - gap;
5619      const bb = this.scroll.y - this.targetBounds[2] - cpb - gap;
5620      const bl = this.scroll.x - this.targetBounds[3] + cpl + gap;
5621      const ob = this.isOutOfBounds([bt, br, bb, bl], x, y);
5622      if (ob) {
5623        const [ disabledX, disabledY ] = this.disabled;
5624        const destX = clamp$1(snap$1(x, this.snapX), bl, br);
5625        const destY = clamp$1(snap$1(y, this.snapY), bt, bb);
5626        const dur = isUnd(duration) ? 350 * globals.timeScale : duration;
5627        if (!disabledX && (ob === 1 || ob === 3)) this.animate[this.xProp](destX, dur, ease);
5628        if (!disabledY && (ob === 2 || ob === 3)) this.animate[this.yProp](destY, dur, ease);
5629      }
5630      return this;
5631    }
5632
5633    /**
5634     * @param {MouseEvent|TouchEvent} e
5635     */
5636    handleDown(e) {
5637      const $eTarget = /** @type {HTMLElement} */(e.target);
5638      if (this.grabbed || /** @type {HTMLInputElement} */($eTarget).type === 'range') return;
5639
5640      e.stopPropagation();
5641
5642      this.grabbed = true;
5643      this.released = false;
5644      this.stop();
5645      this.updateBoundingValues();
5646      const touches = /** @type {TouchEvent} */(e).changedTouches;
5647      const eventX = touches ? touches[0].clientX : /** @type {MouseEvent} */(e).clientX;
5648      const eventY = touches ? touches[0].clientY : /** @type {MouseEvent} */(e).clientY;
5649      const { x, y } = this.transforms.normalizePoint(eventX, eventY);
5650      const [ ct, cr, cb, cl ] = this.containerBounds;
5651      const cf = (1 - this.containerFriction) * this.dragSpeed;
5652      const cx = this.x;
5653      const cy = this.y;
5654      this.coords[0] = this.coords[2] = !cf ? cx : cx > cr ? cr + (cx - cr) / cf : cx < cl ? cl + (cx - cl) / cf : cx;
5655      this.coords[1] = this.coords[3] = !cf ? cy : cy > cb ? cb + (cy - cb) / cf : cy < ct ? ct + (cy - ct) / cf : cy;
5656      this.pointer[0] = x;
5657      this.pointer[1] = y;
5658      this.pointer[2] = x;
5659      this.pointer[3] = y;
5660      this.pointer[4] = x;
5661      this.pointer[5] = y;
5662      this.pointer[6] = x;
5663      this.pointer[7] = y;
5664      this.deltaX = 0;
5665      this.deltaY = 0;
5666      this.velocity = 0;
5667      this.velocityStack[0] = 0;
5668      this.velocityStack[1] = 0;
5669      this.velocityStack[2] = 0;
5670      this.velocityStackIndex = 0;
5671      this.angle = 0;
5672      if (this.targetStyles) {
5673        this.targetStyles.revert();
5674        this.targetStyles = null;
5675      }
5676      const z = /** @type {Number} */(get(this.$target, 'zIndex', false));
5677      zIndex = (z > zIndex ? z : zIndex) + 1;
5678      this.targetStyles = set(this.$target, { zIndex });
5679      if (this.triggerStyles) {
5680        this.triggerStyles.revert();
5681        this.triggerStyles = null;
5682      }
5683      if (this.cursorStyles) {
5684        this.cursorStyles.revert();
5685        this.cursorStyles = null;
5686      }
5687      if (this.isFinePointer && this.cursor) {
5688        this.bodyStyles = set(doc.body, {
5689          cursor: /** @type {DraggableCursorParams} */(this.cursor).onGrab
5690        });
5691      }
5692      this.scrollInView(100, 0, eases.out(3));
5693      this.onGrab(this);
5694
5695      doc.addEventListener('touchmove', this);
5696      doc.addEventListener('touchend', this);
5697      doc.addEventListener('touchcancel', this);
5698      doc.addEventListener('mousemove', this);
5699      doc.addEventListener('mouseup', this);
5700      doc.addEventListener('selectstart', this);
5701    }
5702
5703    /**
5704     * @param {MouseEvent|TouchEvent} e
5705     */
5706    handleMove(e) {
5707      if (!this.grabbed) return;
5708      const touches = /** @type {TouchEvent} */(e).changedTouches;
5709      const eventX = touches ? touches[0].clientX : /** @type {MouseEvent} */(e).clientX;
5710      const eventY = touches ? touches[0].clientY : /** @type {MouseEvent} */(e).clientY;
5711      const { x, y } = this.transforms.normalizePoint(eventX, eventY);
5712      const movedX = x - this.pointer[6];
5713      const movedY = y - this.pointer[7];
5714
5715      let $parent = /** @type {HTMLElement} */(e.target);
5716      let isAtTop = false;
5717      let isAtBottom = false;
5718      let canTouchScroll = false;
5719
5720      while (touches && $parent && $parent !== this.$trigger) {
5721        const overflowY = get($parent, 'overflow-y');
5722        if (overflowY !== 'hidden' && overflowY !== 'visible') {
5723          const { scrollTop, scrollHeight, clientHeight } = $parent;
5724          if (scrollHeight > clientHeight) {
5725            canTouchScroll = true;
5726            isAtTop = scrollTop <= 3;
5727            isAtBottom = scrollTop >= (scrollHeight - clientHeight) - 3;
5728            break;
5729          }
5730        }
5731        $parent = $parent.parentElement;
5732      }
5733
5734      if (canTouchScroll && ((!isAtTop && !isAtBottom) || (isAtTop && movedY < 0) || (isAtBottom && movedY > 0))) {
5735
5736        this.pointer[0] = x;
5737        this.pointer[1] = y;
5738        this.pointer[2] = x;
5739        this.pointer[3] = y;
5740        this.pointer[4] = x;
5741        this.pointer[5] = y;
5742        this.pointer[6] = x;
5743        this.pointer[7] = y;
5744
5745      } else {
5746
5747        preventDefault(e);
5748
5749        // Needed to prevents click on handleUp
5750        if (!this.triggerStyles) this.triggerStyles = set(this.$trigger, { pointerEvents: 'none' });
5751        // Needed to prevent page scroll while dragging on touch devvice
5752        this.$trigger.addEventListener('touchstart', preventDefault, { passive: false });
5753        this.$trigger.addEventListener('touchmove', preventDefault, { passive: false });
5754        this.$trigger.addEventListener('touchend', preventDefault);
5755
5756        // Don't check for a miminim distance move if already dragging
5757        if (this.dragged || (!this.disabled[0] && abs(movedX) > this.dragThreshold) || (!this.disabled[1] && abs(movedY) > this.dragThreshold)) {
5758          this.updateTicker.resume();
5759          this.pointer[2] = this.pointer[0];
5760          this.pointer[3] = this.pointer[1];
5761          this.pointer[0] = x;
5762          this.pointer[1] = y;
5763          this.dragged = true;
5764          this.released = false;
5765          this.onDrag(this);
5766        }
5767      }
5768    }
5769
5770    handleUp() {
5771
5772      if (!this.grabbed) return;
5773
5774      this.updateTicker.pause();
5775
5776      if (this.triggerStyles) {
5777        this.triggerStyles.revert();
5778        this.triggerStyles = null;
5779      }
5780
5781      if (this.bodyStyles) {
5782        this.bodyStyles.revert();
5783        this.bodyStyles = null;
5784      }
5785
5786      const [ disabledX, disabledY ] = this.disabled;
5787      const [ px1, py1, px2, py2, px3, py3 ] = this.pointer;
5788      const [ ct, cr, cb, cl ] = this.containerBounds;
5789      const [ sx, sy ] = this.snapped;
5790      const springX = this.releaseXSpring;
5791      const springY = this.releaseYSpring;
5792      const releaseEase = this.releaseEase;
5793      const hasReleaseSpring = this.hasReleaseSpring;
5794      const overshootCoords = this.overshootCoords;
5795      const cx = this.x;
5796      const cy = this.y;
5797      const pv = this.computeVelocity(px1 - px3, py1 - py3);
5798      const pa = this.angle = atan2(py1 - py2, px1 - px2);
5799      const ds = pv * 150;
5800      const cf = (1 - this.releaseContainerFriction) * this.dragSpeed;
5801      const nx = cx + (cos(pa) * ds);
5802      const ny = cy + (sin(pa) * ds);
5803      const bx = nx > cr ? cr + (nx - cr) * cf : nx < cl ? cl + (nx - cl) * cf : nx;
5804      const by = ny > cb ? cb + (ny - cb) * cf : ny < ct ? ct + (ny - ct) * cf : ny;
5805      const dx = this.destX = clamp$1(round$1(snap$1(bx, this.snapX), 5), cl, cr);
5806      const dy = this.destY = clamp$1(round$1(snap$1(by, this.snapY), 5), ct, cb);
5807      const ob = this.isOutOfBounds(this.containerBounds, nx, ny);
5808
5809      let durationX = 0;
5810      let durationY = 0;
5811      let easeX = releaseEase;
5812      let easeY = releaseEase;
5813      let longestReleaseDuration = 0;
5814
5815      overshootCoords.x = cx;
5816      overshootCoords.y = cy;
5817
5818      if (!disabledX) {
5819        const directionX = dx === cr ? cx > cr ? -1 : 1 : cx < cl ? -1 : 1;
5820        const distanceX = round$1(cx - dx, 0);
5821        springX.velocity = disabledY && hasReleaseSpring ? distanceX ? (ds * directionX) / abs(distanceX) : 0 : pv;
5822        const { ease, settlingDuration, restDuration } = springX;
5823        durationX = cx === dx ? 0 : hasReleaseSpring ? settlingDuration : settlingDuration - (restDuration * globals.timeScale);
5824        if (hasReleaseSpring) easeX = ease;
5825        if (durationX > longestReleaseDuration) longestReleaseDuration = durationX;
5826      }
5827
5828      if (!disabledY) {
5829        const directionY = dy === cb ? cy > cb ? -1 : 1 : cy < ct ? -1 : 1;
5830        const distanceY = round$1(cy - dy, 0);
5831        springY.velocity = disabledX && hasReleaseSpring ? distanceY ? (ds * directionY) / abs(distanceY) : 0 : pv;
5832        const { ease, settlingDuration, restDuration } = springY;
5833        durationY = cy === dy ? 0 : hasReleaseSpring ? settlingDuration : settlingDuration - (restDuration * globals.timeScale);
5834        if (hasReleaseSpring) easeY = ease;
5835        if (durationY > longestReleaseDuration) longestReleaseDuration = durationY;
5836      }
5837
5838      if (!hasReleaseSpring && ob && cf && (durationX || durationY)) {
5839
5840          const composition = compositionTypes.blend;
5841
5842          new JSAnimation(overshootCoords, {
5843            x: { to: bx, duration: durationX * .65 },
5844            y: { to: by, duration: durationY * .65 },
5845            ease: releaseEase,
5846            composition,
5847          }).init();
5848
5849          new JSAnimation(overshootCoords, {
5850            x: { to: dx, duration: durationX },
5851            y: { to: dy, duration: durationY },
5852            ease: releaseEase,
5853            composition,
5854          }).init();
5855
5856          this.overshootTicker.stretch(max(durationX, durationY)).restart();
5857
5858      } else {
5859
5860        if (!disabledX) this.animate[this.xProp](dx, durationX, easeX);
5861        if (!disabledY) this.animate[this.yProp](dy, durationY, easeY);
5862
5863      }
5864
5865      this.scrollInView(longestReleaseDuration, this.scrollThreshold, releaseEase);
5866
5867      let hasSnapped = false;
5868
5869      if (dx !== sx) {
5870        this.snapped[0] = dx;
5871        if (this.snapX) hasSnapped = true;
5872      }
5873
5874      if (dy !== sy && this.snapY) {
5875        this.snapped[1] = dy;
5876        if (this.snapY) hasSnapped = true;
5877      }
5878
5879      if (hasSnapped) this.onSnap(this);
5880
5881      this.grabbed = false;
5882      this.dragged = false;
5883      this.updated = true;
5884      this.released = true;
5885
5886      // It's important to trigger the callback after the release animations to be able to cancel them
5887      this.onRelease(this);
5888
5889      this.$trigger.removeEventListener('touchstart', preventDefault);
5890      this.$trigger.removeEventListener('touchmove', preventDefault);
5891      this.$trigger.removeEventListener('touchend', preventDefault);
5892
5893      doc.removeEventListener('touchmove', this);
5894      doc.removeEventListener('touchend', this);
5895      doc.removeEventListener('touchcancel', this);
5896      doc.removeEventListener('mousemove', this);
5897      doc.removeEventListener('mouseup', this);
5898      doc.removeEventListener('selectstart', this);
5899    }
5900
5901    reset() {
5902      this.stop();
5903      this.resizeTicker.pause();
5904      this.grabbed = false;
5905      this.dragged = false;
5906      this.updated = false;
5907      this.released = false;
5908      this.canScroll = false;
5909      this.setX(0, true);
5910      this.setY(0, true);
5911      this.coords[0] = 0;
5912      this.coords[1] = 0;
5913      this.pointer[0] = 0;
5914      this.pointer[1] = 0;
5915      this.pointer[2] = 0;
5916      this.pointer[3] = 0;
5917      this.pointer[4] = 0;
5918      this.pointer[5] = 0;
5919      this.pointer[6] = 0;
5920      this.pointer[7] = 0;
5921      this.velocity = 0;
5922      this.velocityStack[0] = 0;
5923      this.velocityStack[1] = 0;
5924      this.velocityStack[2] = 0;
5925      this.velocityStackIndex = 0;
5926      this.angle = 0;
5927      return this;
5928    }
5929
5930    enable() {
5931      if (!this.enabled) {
5932        this.enabled = true;
5933        this.$target.classList.remove('is-disabled');
5934        this.touchActionStyles = set(this.$trigger, {
5935          touchAction: this.disabled[0] ? 'pan-x' : this.disabled[1] ? 'pan-y' : 'none'
5936        });
5937        this.$trigger.addEventListener('touchstart', this, { passive: true });
5938        this.$trigger.addEventListener('mousedown', this, { passive: true });
5939        this.$trigger.addEventListener('mouseenter', this);
5940      }
5941      return this;
5942    }
5943
5944    disable() {
5945      this.enabled = false;
5946      this.grabbed = false;
5947      this.dragged = false;
5948      this.updated = false;
5949      this.released = false;
5950      this.canScroll = false;
5951      this.touchActionStyles.revert();
5952      if (this.cursorStyles) {
5953        this.cursorStyles.revert();
5954        this.cursorStyles = null;
5955      }
5956      if (this.triggerStyles) {
5957        this.triggerStyles.revert();
5958        this.triggerStyles = null;
5959      }
5960      if (this.bodyStyles) {
5961        this.bodyStyles.revert();
5962        this.bodyStyles = null;
5963      }
5964      if (this.targetStyles) {
5965        this.targetStyles.revert();
5966        this.targetStyles = null;
5967      }
5968      this.$target.classList.add('is-disabled');
5969      this.$trigger.removeEventListener('touchstart', this);
5970      this.$trigger.removeEventListener('mousedown', this);
5971      this.$trigger.removeEventListener('mouseenter', this);
5972      doc.removeEventListener('touchmove', this);
5973      doc.removeEventListener('touchend', this);
5974      doc.removeEventListener('touchcancel', this);
5975      doc.removeEventListener('mousemove', this);
5976      doc.removeEventListener('mouseup', this);
5977      doc.removeEventListener('selectstart', this);
5978      return this;
5979    }
5980
5981    revert() {
5982      this.reset();
5983      this.disable();
5984      this.$target.classList.remove('is-disabled');
5985      this.updateTicker.revert();
5986      this.overshootTicker.revert();
5987      this.resizeTicker.revert();
5988      this.animate.revert();
5989      this.resizeObserver.disconnect();
5990      return this;
5991    }
5992
5993    /**
5994     * @param {Event} e
5995     */
5996    handleEvent(e) {
5997      switch (e.type) {
5998        case 'mousedown':
5999          this.handleDown(/** @type {MouseEvent} */(e));
6000          break;
6001        case 'touchstart':
6002          this.handleDown(/** @type {TouchEvent} */(e));
6003          break;
6004        case 'mousemove':
6005          this.handleMove(/** @type {MouseEvent} */(e));
6006          break;
6007        case 'touchmove':
6008          this.handleMove(/** @type {TouchEvent} */(e));
6009          break;
6010        case 'mouseup':
6011          this.handleUp();
6012          break;
6013        case 'touchend':
6014          this.handleUp();
6015          break;
6016        case 'touchcancel':
6017          this.handleUp();
6018          break;
6019        case 'mouseenter':
6020          this.handleHover();
6021          break;
6022        case 'selectstart':
6023          preventDefault(e);
6024          break;
6025      }
6026    }
6027  }
6028
6029  /**
6030   * @param {TargetsParam} target
6031   * @param {DraggableParams} [parameters]
6032   * @return {Draggable}
6033   */
6034  const createDraggable = (target, parameters) => new Draggable(target, parameters);
6035
6036  
6037
6038  /**
6039   * @param  {Callback<Timer>} [callback]
6040   * @return {Timer}
6041   */
6042  const sync = (callback = noop) => {
6043    return new Timer({ duration: 1 * globals.timeScale, onComplete: callback }, null, 0).resume();
6044  };
6045
6046  /**
6047   * @
6047param  {(...args: any[]) => Tickable | ((...args: any[]) => void)} constructor
6048   * @return {(...args: any[]) => Tickable | ((...args: any[]) => void)}
6049   */
6050  const keepTime = constructor => {
6051    /** @type {Tickable} */
6052    let tracked;
6053    return (...args) => {
6054      let currentIteration, currentIterationProgress, reversed, alternate;
6055      if (tracked) {
6056        currentIteration = tracked.currentIteration;
6057        currentIterationProgress = tracked.iterationProgress;
6058        reversed = tracked.reversed;
6059        alternate = tracked._alternate;
6060        tracked.revert();
6061      }
6062      const cleanup = constructor(...args);
6063      if (cleanup && !isFnc(cleanup) && cleanup.revert) tracked = cleanup;
6064      if (!isUnd(currentIterationProgress)) {
6065        /** @type {Tickable} */(tracked).currentIteration = currentIteration;
6066        /** @type {Tickable} */(tracked).iterationProgress = (alternate ? !(currentIteration % 2) ? reversed : !reversed : reversed) ? 1 - currentIterationProgress : currentIterationProgress;
6067      }
6068      return cleanup || noop;
6069    }
vendor: 12,365 bytes, lines 6069-6467
6069
6070  };
6071
6072  
6073
6074  class Scope {
6075    /** @param {ScopeParams} [parameters] */
6076    constructor(parameters = {}) {
6077      if (scope.current) scope.current.register(this);
6078      const rootParam = parameters.root;
6079      /** @type {Document|DOMTarget} */
6080      let root = doc;
6081      if (rootParam) {
6082        root = /** @type {ReactRef} */(rootParam).current ||
6083               /** @type {AngularRef} */(rootParam).nativeElement ||
6084               parseTargets(/** @type {DOMTargetSelector} */(rootParam))[0] ||
6085               doc;
6086      }
6087      const scopeDefaults = parameters.defaults;
6088      const globalDefault = globals.defaults;
6089      const mediaQueries = parameters.mediaQueries;
6090      /** @type {DefaultsParams} */
6091      this.defaults = scopeDefaults ? mergeObjects(scopeDefaults, globalDefault) : globalDefault;
6092      /** @type {Document|DOMTarget} */
6093      this.root = root;
6094      /** @type {Array<ScopeConstructorCallback>} */
6095      this.constructors = [];
6096      /** @type {Array<ScopeCleanupCallback>} */
6097      this.revertConstructors = [];
6098      /** @type {Array<Revertible>} */
6099      this.revertibles = [];
6100      /** @type {Array<ScopeConstructorCallback | ((scope: this) => Tickable)>} */
6101      this.constructorsOnce = [];
6102      /** @type {Array<ScopeCleanupCallback>} */
6103      this.revertConstructorsOnce = [];
6104      /** @type {Array<Revertible>} */
6105      this.revertiblesOnce = [];
6106      /** @type {Boolean} */
6107      this.once = false;
6108      /** @type {Number} */
6109      this.onceIndex = 0;
6110      /** @type {Record<String, ScopeMethod>} */
6111      this.methods = {};
6112      /** @type {Record<String, Boolean>} */
6113      this.matches = {};
6114      /** @type {Record<String, MediaQueryList>} */
6115      this.mediaQueryLists = {};
6116      /** @type {Record<String, any>} */
6117      this.data = {};
6118      if (mediaQueries) {
6119        for (let mq in mediaQueries) {
6120          const _mq = win.matchMedia(mediaQueries[mq]);
6121          this.mediaQueryLists[mq] = _mq;
6122          _mq.addEventListener('change', this);
6123        }
6124      }
6125    }
6126
6127    /**
6128     * @param {Revertible} revertible
6129     */
6130    register(revertible) {
6131      const store = this.once ? this.revertiblesOnce : this.revertibles;
6132      store.push(revertible);
6133    }
6134
6135    /**
6136     * @template T
6137     * @param {ScopedCallback<T>} cb
6138     * @return {T}
6139     */
6140    execute(cb) {
6141      let activeScope = scope.current;
6142      let activeRoot = scope.root;
6143      let activeDefaults = globals.defaults;
6144      scope.current = this;
6145      scope.root = this.root;
6146      globals.defaults = this.defaults;
6147      const mqs = this.mediaQueryLists;
6148      for (let mq in mqs) this.matches[mq] = mqs[mq].matches;
6149      const returned = cb(this);
6150      scope.current = activeScope;
6151      scope.root = activeRoot;
6152      globals.defaults = activeDefaults;
6153      return returned;
6154    }
6155
6156    /**
6157     * @return {this}
6158     */
6159    refresh() {
6160      this.onceIndex = 0;
6161      this.execute(() => {
6162        let i = this.revertibles.length;
6163        let y = this.revertConstructors.length;
6164        while (i--) this.revertibles[i].revert();
6165        while (y--) this.revertConstructors[y](this);
6166        this.revertibles.length = 0;
6167        this.revertConstructors.length = 0;
6168        this.constructors.forEach((/** @type {ScopeConstructorCallback} */constructor) => {
6169          const revertConstructor = constructor(this);
6170          if (isFnc(revertConstructor)) {
6171            this.revertConstructors.push(revertConstructor);
6172          }
6173        });
6174      });
6175      return this;
6176    }
6177
6178    /**
6179     * @overload
6180     * @param {String} a1
6181     * @param {ScopeMethod} a2
6182     * @return {this}
6183     *
6184     * @overload
6185     * @param {ScopeConstructorCallback} a1
6186     * @return {this}
6187     *
6188     * @param {String|ScopeConstructorCallback} a1
6189     * @param {ScopeMethod} [a2]
6190     */
6191    add(a1, a2) {
6192      this.once = false;
6193      if (isFnc(a1)) {
6194        const constructor = /** @type {ScopeConstructorCallback} */(a1);
6195        this.constructors.push(constructor);
6196        this.execute(() => {
6197          const revertConstructor = constructor(this);
6198          if (isFnc(revertConstructor)) {
6199            this.revertConstructors.push(revertConstructor);
6200          }
6201        });
6202      } else {
6203        this.methods[/** @type {String} */(a1)] = (/** @type {any} */...args) => this.execute(() => a2(...args));
6204      }
6205      return this;
6206    }
6207
6208    /**
6209     * @param {ScopeConstructorCallback} scopeConstructorCallback
6210     * @return {this}
6211     */
6212    addOnce(scopeConstructorCallback) {
6213      this.once = true;
6214      if (isFnc(scopeConstructorCallback)) {
6215        const currentIndex = this.onceIndex++;
6216        const tracked = this.constructorsOnce[currentIndex];
6217        if (tracked) return this;
6218        const constructor = /** @type {ScopeConstructorCallback} */(scopeConstructorCallback);
6219        this.constructorsOnce[currentIndex] = constructor;
6220        this.execute(() => {
6221          const revertConstructor = constructor(this);
6222          if (isFnc(revertConstructor)) {
6223            this.revertConstructorsOnce.push(revertConstructor);
6224          }
6225        });
6226      }
6227      return this;
6228    }
6229
6230    /**
6231     * @param  {(scope: this) => Tickable} cb
6232     * @return {Tickable}
6233     */
6234    keepTime(cb) {
6235      this.once = true;
6236      const currentIndex = this.onceIndex++;
6237      const tracked = /** @type {(scope: this) => Tickable} */(this.constructorsOnce[currentIndex]);
6238      if (isFnc(tracked)) return tracked(this);
6239      const constructor = /** @type {(scope: this) => Tickable} */(keepTime(cb));
6240      this.constructorsOnce[currentIndex] = constructor;
6241      let trackedTickable;
6242      this.execute(() => {
6243        trackedTickable = constructor(this);
6244      });
6245      return trackedTickable;
6246    }
6247
6248    /**
6249     * @param {Event} e
6250     */
6251    handleEvent(e) {
6252      switch (e.type) {
6253        case 'change':
6254          this.refresh();
6255          break;
6256      }
6257    }
6258
6259    revert() {
6260      const revertibles = this.revertibles;
6261      const revertConstructors = this.revertConstructors;
6262      const revertiblesOnce = this.revertiblesOnce;
6263      const revertConstructorsOnce = this.revertConstructorsOnce;
6264      const mqs = this.mediaQueryLists;
6265      let i = revertibles.length;
6266      let j = revertConstructors.length;
6267      let k = revertiblesOnce.length;
6268      let l = revertConstructorsOnce.length;
6269      while (i--) revertibles[i].revert();
6270      while (j--) revertConstructors[j](this);
6271      while (k--) revertiblesOnce[k].revert();
6272      while (l--) revertConstructorsOnce[l](this);
6273      for (let mq in mqs) mqs[mq].removeEventListener('change', this);
6274      revertibles.length = 0;
6275      revertConstructors.length = 0;
6276      this.constructors.length = 0;
6277      revertiblesOnce.length = 0;
6278      revertConstructorsOnce.length = 0;
6279      this.constructorsOnce.length = 0;
6280      this.onceIndex = 0;
6281      this.matches = {};
6282      this.methods = {};
6283      this.mediaQueryLists = {};
6284      this.data = {};
6285    }
6286  }
6287
6288  /**
6289   * @param {ScopeParams} [params]
6290   * @return {Scope}
6291   */
6292  const createScope = params => new Scope(params);
6293
6294  
6295
6296  
6297
6298  
6299
6300  
6301
6302  /**
6303   * @return {Number}
6304   */
6305  const getMaxViewHeight = () => {
6306    const $el = doc.createElement('div');
6307    doc.body.appendChild($el);
6308    $el.style.height = '100lvh';
6309    const height = $el.offsetHeight;
6310    doc.body.removeChild($el);
6311    return height;
6312  };
6313
6314  /**
6315   * @template {ScrollThresholdValue|String|Number|Boolean|Function|Object} T
6316   * @param {T | ((observer: ScrollObserver) => T)} value
6317   * @param {ScrollObserver} scroller
6318   * @return {T}
6319   */
6320  const parseScrollObserverFunctionParameter = (value, scroller) => value && isFnc(value) ? /** @type {Function} */(value)(scroller) : /** @type {T} */(value);
6321
6322  const scrollContainers = new Map();
6323
6324  class ScrollContainer {
6325    /**
6326     * @param {HTMLElement} $el
6327     */
6328    constructor($el) {
6329      /** @type {HTMLElement} */
6330      this.element = $el;
6331      /** @type {Boolean} */
6332      this.useWin = this.element === doc.body;
6333      /** @type {Number} */
6334      this.winWidth = 0;
6335      /** @type {Number} */
6336      this.winHeight = 0;
6337      /** @type {Number} */
6338      this.width = 0;
6339      /** @type {Number} */
6340      this.height = 0;
6341      /** @type {Number} */
6342      this.left = 0;
6343      /** @type {Number} */
6344      this.top = 0;
6345      /** @type {Number} */
6346      this.scale = 1;
6347      /** @type {Number} */
6348      this.zIndex = 0;
6349      /** @type {Number} */
6350      this.scrollX = 0;
6351      /** @type {Number} */
6352      this.scrollY = 0;
6353      /** @type {Number} */
6354      this.prevScrollX = 0;
6355      /** @type {Number} */
6356      this.prevScrollY = 0;
6357      /** @type {Number} */
6358      this.scrollWidth = 0;
6359      /** @type {Number} */
6360      this.scrollHeight = 0;
6361      /** @type {Number} */
6362      this.velocity = 0;
6363      /** @type {Boolean} */
6364      this.backwardX = false;
6365      /** @type {Boolean} */
6366      this.backwardY = false;
6367      /** @type {Timer} */
6368      this.scrollTicker = new Timer({
6369        autoplay: false,
6370        onBegin: () => this.dataTimer.resume(),
6371        onUpdate: () => {
6372          const backwards = this.backwardX || this.backwardY;
6373          forEachChildren(this, (/** @type {ScrollObserver} */child) => child.handleScroll(), backwards);
6374        },
6375        onComplete: () => this.dataTimer.pause()
6376      }).init();
6377      /** @type {Timer} */
6378      this.dataTimer = new Timer({
6379        autoplay: false,
6380        frameRate: 30,
6381        onUpdate: (/** @type {Timer} */self) => {
6382          const dt = self.deltaTime;
6383          const px = this.prevScrollX;
6384          const py = this.prevScrollY;
6385          const nx = this.scrollX;
6386          const ny = this.scrollY;
6387          const dx = px - nx;
6388          const dy = py - ny;
6389          this.prevScrollX = nx;
6390          this.prevScrollY = ny;
6391          if (dx) this.backwardX = px > nx;
6392          if (dy) this.backwardY = py > ny;
6393          this.velocity = round$1(dt > 0 ? Math.sqrt(dx * dx + dy * dy) / dt : 0, 5);
6394        }
6395      }).init();
6396      /** @type {Timer} */
6397      this.resizeTicker = new Timer({
6398        autoplay: false,
6399        duration: 250 * globals.timeScale,
6400        onComplete: () => {
6401          this.updateWindowBounds();
6402          this.refreshScrollObservers();
6403          this.handleScroll();
6404        }
6405      }).init();
6406      /** @type {Timer} */
6407      this.wakeTicker = new Timer({
6408        autoplay: false,
6409        duration: 500 * globals.timeScale,
6410        onBegin: () => {
6411          this.scrollTicker.resume();
6412        },
6413        onComplete: () => {
6414          this.scrollTicker.pause();
6415        }
6416      }).init();
6417      /** @type {ScrollObserver} */
6418      this._head = null;
6419      /** @type {ScrollObserver} */
6420      this._tail = null;
6421      this.updateScrollCoords();
6422      this.updateWindowBounds();
6423      this.updateBounds();
6424      this.refreshScrollObservers();
6425      this.handleScroll();
6426      this.resizeObserver = new ResizeObserver(() => this.resizeTicker.restart());
6427      this.resizeObserver.observe(this.element);
6428      (this.useWin ? win : this.element).addEventListener('scroll', this, false);
6429    }
6430
6431    updateScrollCoords() {
6432      const useWin = this.useWin;
6433      const $el = this.element;
6434      this.scrollX = round$1(useWin ? win.scrollX : $el.scrollLeft, 0);
6435      this.scrollY = round$1(useWin ? win.scrollY : $el.scrollTop, 0);
6436    }
6437
6438    updateWindowBounds() {
6439      this.winWidth = win.innerWidth;
6440      this.winHeight = getMaxViewHeight();
6441    }
6442
6443    updateBounds() {
6444      const style = getComputedStyle(this.element);
6445      const $el = this.element;
6446      this.scrollWidth = $el.scrollWidth + parseFloat(style.marginLeft) + parseFloat(style.marginRight);
6447      this.scrollHeight = $el.scrollHeight + parseFloat(style.marginTop) + parseFloat(style.marginBottom);
6448      this.updateWindowBounds();
6449      let width, height;
6450      if (this.useWin) {
6451        width = this.winWidth;
6452        height = this.winHeight;
6453      } else {
6454        const elRect = $el.getBoundingClientRect();
6455        width = $el.clientWidth;
6456        height = $el.clientHeight;
6457        this.top = elRect.top;
6458        this.left = elRect.left;
6459        this.scale = elRect.width ? width / elRect.width : (elRect.height ? height / elRect.height : 1);
6460      }
6461      this.width = width;
6462      this.height = height;
6463    }
6464
6465    refreshScrollObservers() {
6466      forEachChildren(this, (/** @type {ScrollObserver} */child) => {
6467        if (
6467child._debug) {
6468          child.removeDebug();
6469        }
6470      });
6471      this.updateBounds();
6472      forEachChildren(this, (/** @type {ScrollObserver} */child) => {
6473        child.refresh(
vendor: 7,877 bytes, lines 6473-6685
6473);
6474        if (child._debug) {
6475          child.debug();
6476        }
6477      });
6478    }
6479
6480    refresh() {
6481      this.updateWindowBounds();
6482      this.updateBounds();
6483      this.refreshScrollObservers();
6484      this.handleScroll();
6485    }
6486
6487    handleScroll() {
6488      this.updateScrollCoords();
6489      this.wakeTicker.restart();
6490    }
6491
6492    /**
6493     * @param {Event} e
6494     */
6495    handleEvent(e) {
6496      switch (e.type) {
6497        case 'scroll':
6498          this.handleScroll();
6499          break;
6500      }
6501    }
6502
6503    revert() {
6504      this.scrollTicker.cancel();
6505      this.dataTimer.cancel();
6506      this.resizeTicker.cancel();
6507      this.wakeTicker.cancel();
6508      this.resizeObserver.disconnect();
6509      (this.useWin ? win : this.element).removeEventListener('scroll', this);
6510      scrollContainers.delete(this.element);
6511    }
6512  }
6513
6514  /**
6515   * @param {TargetsParam} target
6516   * @return {ScrollContainer}
6517   */
6518  const registerAndGetScrollContainer = target => {
6519    const $el = /** @type {HTMLElement} */(target ? parseTargets(target)[0] || doc.body : doc.body);
6520    let scrollContainer = scrollContainers.get($el);
6521    if (!scrollContainer) {
6522      scrollContainer = new ScrollContainer($el);
6523      scrollContainers.set($el, scrollContainer);
6524    }
6525    return scrollContainer;
6526  };
6527
6528  /**
6529   * @param {HTMLElement} $el
6530   * @param {Number|string} v
6531   * @param {Number} size
6532   * @param {Number} [under]
6533   * @param {Number} [over]
6534   * @return {Number}
6535   */
6536  const convertValueToPx = ($el, v, size, under, over) => {
6537    const clampMin = v === 'min';
6538    const clampMax = v === 'max';
6539    const value = v === 'top' || v === 'left' || v === 'start' || clampMin ? 0 :
6540                  v === 'bottom' || v === 'right' || v === 'end' || clampMax ? '100%' :
6541                  v === 'center' ? '50%' :
6542                  v;
6543    const { n, u } = decomposeRawValue(value, decomposedOriginalValue);
6544    let px = n;
6545    if (u === '%') {
6546      px = (n / 100) * size;
6547    } else if (u) {
6548      px = convertValueUnit($el, decomposedOriginalValue, 'px', true).n;
6549    }
6550    if (clampMax && under < 0) px += under;
6551    if (clampMin && over > 0) px += over;
6552    return px;
6553  };
6554
6555  /**
6556   * @param {HTMLElement} $el
6557   * @param {ScrollThresholdValue} v
6558   * @param {Number} size
6559   * @param {Number} [under]
6560   * @param {Number} [over]
6561   * @return {Number}
6562   */
6563  const parseBoundValue = ($el, v, size, under, over) => {
6564    /** @type {Number} */
6565    let value;
6566    if (isStr(v)) {
6567      const matchedOperator = relativeValuesExecRgx.exec(/** @type {String} */(v));
6568      if (matchedOperator) {
6569        const splitter = matchedOperator[0];
6570        const operator = splitter[0];
6571        const splitted = /** @type {String} */(v).split(splitter);
6572        const clampMin = splitted[0] === 'min';
6573        const clampMax = splitted[0] === 'max';
6574        const valueAPx = convertValueToPx($el, splitted[0], size, under, over);
6575        const valueBPx = convertValueToPx($el, splitted[1], size, under, over);
6576        if (clampMin) {
6577          const min = getRelativeValue(convertValueToPx($el, 'min', size), valueBPx, operator);
6578          value = min < valueAPx ? valueAPx : min;
6579        } else if (clampMax) {
6580          const max = getRelativeValue(convertValueToPx($el, 'max', size), valueBPx, operator);
6581          value = max > valueAPx ? valueAPx : max;
6582        } else {
6583          value = getRelativeValue(valueAPx, valueBPx, operator);
6584        }
6585      } else {
6586        value = convertValueToPx($el, v, size, under, over);
6587      }
6588    } else {
6589      value = /** @type {Number} */(v);
6590    }
6591    return round$1(value, 0);
6592  };
6593
6594  /**
6595   * @param {JSAnimation} linked
6596   * @return {HTMLElement}
6597   */
6598  const getAnimationDomTarget = linked => {
6599    let $linkedTarget;
6600    const linkedTargets = linked.targets;
6601    for (let i = 0, l = linkedTargets.length; i < l; i++) {
6602      const target = linkedTargets[i];
6603      if (target[isDomSymbol]) {
6604        $linkedTarget = /** @type {HTMLElement} */(target);
6605        break;
6606      }
6607    }
6608    return $linkedTarget;
6609  };
6610
6611  let scrollerIndex = 0;
6612
6613  const debugColors$1 = ['#FF4B4B','#FF971B','#FFC730','#F9F640','#7AFF5A','#18FF74','#17E09B','#3CFFEC','#05DBE9','#33B3F1','#638CF9','#C563FE','#FF4FCF','#F93F8A'];
6614
6615  class ScrollObserver {
6616    /**
6617     * @param {ScrollObserverParams} parameters
6618     */
6619    constructor(parameters = {}) {
6620      if (scope.current) scope.current.register(this);
6621      const syncMode = setValue(parameters.sync, 'play pause');
6622      const ease = syncMode ? parseEase(/** @type {EasingParam} */(syncMode)) : null;
6623      const isLinear = syncMode && (syncMode === 'linear' || syncMode === none);
6624      const isEase = syncMode && !(ease === none && !isLinear);
6625      const isSmooth = syncMode && (isNum(syncMode) || syncMode === true || isLinear);
6626      const isMethods = syncMode && (isStr(syncMode) && !isEase && !isSmooth);
6627      const syncMethods = isMethods ? /** @type {String} */(syncMode).split(' ').map(
6628        (/** @type {String} */m) => () => {
6629          const linked = this.linked;
6630          return linked && linked[m] ? linked[m]() : null;
6631        }
6632      ) : null;
6633      const biDirSync = isMethods && syncMethods.length > 2;
6634      /** @type {Number} */
6635      this.index = scrollerIndex++;
6636      /** @type {String|Number} */
6637      this.id = !isUnd(parameters.id) ? parameters.id : this.index;
6638      /** @type {ScrollContainer} */
6639      this.container = registerAndGetScrollContainer(parameters.container);
6640      /** @type {HTMLElement} */
6641      this.target = null;
6642      /** @type {Tickable|WAAPIAnimation} */
6643      this.linked = null;
6644      /** @type {Boolean} */
6645      this.repeat = null;
6646      /** @type {Boolean} */
6647      this.horizontal = null;
6648      /** @type {ScrollThresholdParam|ScrollThresholdValue|ScrollThresholdCallback} */
6649      this.enter = null;
6650      /** @type {ScrollThresholdParam|ScrollThresholdValue|ScrollThresholdCallback} */
6651      this.leave = null;
6652      /** @type {Boolean} */
6653      this.sync = isEase || isSmooth || !!syncMethods;
6654      /** @type {EasingFunction} */
6655      this.syncEase = isEase ? ease : null;
6656      /** @type {Number} */
6657      this.syncSmooth = isSmooth ? syncMode === true || isLinear ? 1 : /** @type {Number} */(syncMode) : null;
6658      /** @type {Callback<ScrollObserver>} */
6659      this.onSyncEnter = syncMethods && !biDirSync && syncMethods[0] ? syncMethods[0] : noop;
6660      /** @type {Callback<ScrollObserver>} */
6661      this.onSyncLeave = syncMethods && !biDirSync && syncMethods[1] ? syncMethods[1] : noop;
6662      /** @type {Callback<ScrollObserver>} */
6663      this.onSyncEnterForward = syncMethods && biDirSync && syncMethods[0] ? syncMethods[0] : noop;
6664      /** @type {Callback<ScrollObserver>} */
6665      this.onSyncLeaveForward = syncMethods && biDirSync && syncMethods[1] ? syncMethods[1] : noop;
6666      /** @type {Callback<ScrollObserver>} */
6667      this.onSyncEnterBackward = syncMethods && biDirSync && syncMethods[2] ? syncMethods[2] : noop;
6668      /** @type {Callback<ScrollObserver>} */
6669      this.onSyncLeaveBackward = syncMethods && biDirSync && syncMethods[3] ? syncMethods[3] : noop;
6670      /** @type {Callback<ScrollObserver>} */
6671      this.onEnter = parameters.onEnter || noop;
6672      /** @type {Callback<ScrollObserver>} */
6673      this.onLeave = parameters.onLeave || noop;
6674      /** @type {Callback<ScrollObserver>} */
6675      this.onEnterForward = parameters.onEnterForward || noop;
6676      /** @type {Callback<ScrollObserver>} */
6677      this.onLeaveForward = parameters.onLeaveForward || noop;
6678      /** @type {Callback<ScrollObserver>} */
6679      this.onEnterBackward = parameters.onEnterBackward || noop;
6680      /** @type {Callback<ScrollObserver>} */
6681      this.onLeaveBackward = parameters.onLeaveBackward || noop;
6682      /** @type {Callback<ScrollObserver>} */
6683      this.onUpdate = parameters.onUpdate || noop;
6684      /** @type {Callback<ScrollObserver>} */
6685      this.on
vendor: 2,172 bytes, lines 6685-6748
6685SyncComplete = parameters.onSyncComplete || noop;
6686      /** @type {Boolean} */
6687      this.reverted = false;
6688      /** @type {Boolean} */
6689      this.ready = false;
6690      /** @type {Boolean} */
6691      this.completed = false;
6692      /** @type {Boolean} */
6693      this.began = false;
6694      /** @type {Boolean} */
6695      this.isInView = false;
6696      /** @type {Boolean} */
6697      this.forceEnter = false;
6698      /** @type {Boolean} */
6699      this.hasEntered = false;
6700      /** @type {Number} */
6701      this.offset = 0;
6702      /** @type {Number} */
6703      this.offsetStart = 0;
6704      /** @type {Number} */
6705      this.offsetEnd = 0;
6706      /** @type {Number} */
6707      this.distance = 0;
6708      /** @type {Number} */
6709      this.prevProgress = 0;
6710      /** @type {Array} */
6711      this.thresholds = ['start', 'end', 'end', 'start'];
6712      /** @type {[Number, Number, Number, Number]} */
6713      this.coords = [0, 0, 0, 0];
6714      /** @type {JSAnimation} */
6715      this.debugStyles = null;
6716      /** @type {HTMLElement} */
6717      this.$debug = null;
6718      /** @type {ScrollObserverParams} */
6719      this._params = parameters;
6720      /** @type {Boolean} */
6721      this._debug = setValue(parameters.debug, false);
6722      /** @type {ScrollObserver} */
6723      this._next = null;
6724      /** @type {ScrollObserver} */
6725      this._prev = null;
6726      addChild(this.container, this);
6727      // Wait for the next frame to add to the container in order to handle calls to link()
6728      sync(() => {
6729        if (this.reverted) return;
6730        if (!this.target) {
6731          const target = /** @type {HTMLElement} */(parseTargets(parameters.target)[0]);
6732          this.target = target || doc.body;
6733          this.refresh();
6734        }
6735        if (this._debug) this.debug();
6736      });
6737    }
6738
6739    /**
6740     * @param {Tickable|WAAPIAnimation} linked
6741     */
6742    link(linked) {
6743      if (linked) {
6744        // Make sure to pause the linked object in case it's added later
6745        linked.pause();
6746        this.linked = linked;
6747        // Forces WAAPI Animation to persist; otherwise, they will stop syncing on finish.
6748        if (!isUnd(/** @type {WAAPIAnimation} */(linked))) /** @type {WAAPIAnimation} */(linked).persist = true;
vendor: 8,702 bytes, lines 6748-6950
6748
6749        // Try to use a target of the linked object if no target parameters specified
6750        if (!this._params.target) {
6751          /** @type {HTMLElement} */
6752          let $linkedTarget;
6753          if (!isUnd(/** @type {JSAnimation} */(linked).targets)) {
6754            $linkedTarget = getAnimationDomTarget(/** @type {JSAnimation} */(linked));
6755          } else {
6756            forEachChildren(/** @type {Timeline} */(linked), (/** @type {JSAnimation} */child) => {
6757              if (child.targets && !$linkedTarget) {
6758                $linkedTarget = getAnimationDomTarget(/** @type {JSAnimation} */(child));
6759              }
6760            });
6761          }
6762          // Fallback to body if no target found
6763          this.target = $linkedTarget || doc.body;
6764          this.refresh();
6765        }
6766      }
6767      return this;
6768    }
6769
6770    get velocity() {
6771      return this.container.velocity;
6772    }
6773
6774    get backward() {
6775      return this.horizontal ? this.container.backwardX : this.container.backwardY;
6776    }
6777
6778    get scroll() {
6779      return this.horizontal ? this.container.scrollX : this.container.scrollY;
6780    }
6781
6782    get progress() {
6783      const p = (this.scroll - this.offsetStart) / this.distance;
6784      return p === Infinity || isNaN(p) ? 0 : round$1(clamp$1(p, 0, 1), 6);
6785    }
6786
6787    refresh() {
6788      // This flag is used to prevent running handleScroll() outside of this.refresh() with values not yet calculated
6789      this.ready = true;
6790      this.reverted = false;
6791      const params = this._params;
6792      this.repeat = setValue(parseScrollObserverFunctionParameter(params.repeat, this), true);
6793      this.horizontal = setValue(parseScrollObserverFunctionParameter(params.axis, this), 'y') === 'x';
6794      this.enter = setValue(parseScrollObserverFunctionParameter(params.enter, this), 'end start');
6795      this.leave = setValue(parseScrollObserverFunctionParameter(params.leave, this), 'start end');
6796      this.updateBounds();
6797      this.handleScroll();
6798      return this;
6799    }
6800
6801    removeDebug() {
6802      if (this.$debug) {
6803        this.$debug.parentNode.removeChild(this.$debug);
6804        this.$debug = null;
6805      }
6806      if (this.debugStyles) {
6807        this.debugStyles.revert();
6808        this.$debug = null;
6809      }
6810      return this;
6811    }
6812
6813    debug() {
6814      this.removeDebug();
6815      const container = this.container;
6816      const isHori = this.horizontal;
6817      const $existingDebug = container.element.querySelector(':scope > .animejs-onscroll-debug');
6818      const $debug = doc.createElement('div');
6819      const $thresholds = doc.createElement('div');
6820      const $triggers = doc.createElement('div');
6821      const color = debugColors$1[this.index % debugColors$1.length];
6822      const useWin = container.useWin;
6823      const containerWidth = useWin ? container.winWidth : container.width;
6824      const containerHeight = useWin ? container.winHeight : container.height;
6825      const scrollWidth = container.scrollWidth;
6826      const scrollHeight = container.scrollHeight;
6827      const size = this.container.width > 360 ? 320 : 260;
6828      const offLeft = isHori ? 0 : 10;
6829      const offTop = isHori ? 10 : 0;
6830      const half = isHori ? 24 : size / 2;
6831      const labelHeight = isHori ? half : 15;
6832      const labelWidth = isHori ? 60 : half;
6833      const labelSize = isHori ? labelWidth : labelHeight;
6834      const repeat = isHori ? 'repeat-x' : 'repeat-y';
6835      /**
6836       * @param {Number} v
6837       * @return {String}
6838       */
6839      const gradientOffset = v => isHori ? '0px '+(v)+'px' : (v)+'px'+' 2px';
6840      /**
6841       * @param {String} c
6842       * @return {String}
6843       */
6844      const lineCSS = (c) => `linear-gradient(${isHori ? 90 : 0}deg, ${c} 2px, transparent 1px)`;
6845      /**
6846       * @param {String} p
6847       * @param {Number} l
6848       * @param {Number} t
6849       * @param {Number} w
6850       * @param {Number} h
6851       * @return {String}
6852       */
6853      const baseCSS = (p, l, t, w, h) => `position:${p};left:${l}px;top:${t}px;width:${w}px;height:${h}px;`;
6854      $debug.style.cssText = `${baseCSS('absolute', offLeft, offTop, isHori ? scrollWidth : size, isHori ? size : scrollHeight)}
6855      pointer-events: none;
6856      z-index: ${this.container.zIndex++};
6857      display: flex;
6858      flex-direction: ${isHori ? 'column' : 'row'};
6859      filter: drop-shadow(0px 1px 0px rgba(0,0,0,.75));
6860    `;
6861      $thresholds.style.cssText = `${baseCSS('sticky', 0, 0, isHori ? containerWidth : half, isHori ? half : containerHeight)}`;
6862      if (!$existingDebug) {
6863        $thresholds.style.cssText += `background:
6864        ${lineCSS('#FFFF')}${gradientOffset(half-10)} / ${isHori ? '100px 100px' : '100px 100px'} ${repeat},
6865        ${lineCSS('#FFF8')}${gradientOffset(half-10)} / ${isHori ? '10px 10px' : '10px 10px'} ${repeat};
6866      `;
6867      }
6868      $triggers.style.cssText = `${baseCSS('relative', 0, 0, isHori ? scrollWidth : half, isHori ? half : scrollHeight)}`;
6869      if (!$existingDebug) {
6870        $triggers.style.cssText += `background:
6871        ${lineCSS('#FFFF')}${gradientOffset(0)} / ${isHori ? '100px 10px' : '10px 100px'} ${repeat},
6872        ${lineCSS('#FFF8')}${gradientOffset(0)} / ${isHori ? '10px 0px' : '0px 10px'} ${repeat};
6873      `;
6874      }
6875      const labels = [' enter: ', ' leave: '];
6876      this.coords.forEach((v, i) => {
6877        const isView = i > 1;
6878        const value = (isView ? 0 : this.offset) + v;
6879        const isTail = i % 2;
6880        const isFirst = value < labelSize;
6881        const isOver = value > (isView ? isHori ? containerWidth : containerHeight : isHori ? scrollWidth : scrollHeight) - labelSize;
6882        const isFlip = (isView ? isTail && !isFirst : !isTail && !isFirst) || isOver;
6883        const $label = doc.createElement('div');
6884        const $text = doc.createElement('div');
6885        const dirProp = isHori ? isFlip ? 'right' : 'left' : isFlip ? 'bottom' : 'top';
6886        const flipOffset = isFlip ? (isHori ? labelWidth : labelHeight) + (!isView ? isHori ? -1 : -2 : isHori ? -1 : isOver ? 0 : -2) : !isView ? isHori ? 1 : 0 : isHori ? 1 : 0;
6887        // $text.innerHTML = `${!isView ? '' : labels[isTail] + ' '}${this.id}: ${this.thresholds[i]} ${isView ? '' : labels[isTail]}`;
6888        $text.innerHTML = `${this.id}${labels[isTail]}${this.thresholds[i]}`;
6889        $label.style.cssText = `${baseCSS('absolute', 0, 0, labelWidth, labelHeight)}
6890        display: flex;
6891        flex-direction: ${isHori ? 'column' : 'row'};
6892        justify-content: flex-${isView ? 'start' : 'end'};
6893        align-items: flex-${isFlip ? 'end' : 'start'};
6894        border-${dirProp}: 2px ${isTail ? 'solid' : 'solid'} ${color};
6895      `;
6896        $text.style.cssText = `
6897        overflow: hidden;
6898        max-width: ${(size / 2) - 10}px;
6899        height: ${labelHeight};
6900        margin-${isHori ? isFlip ? 'right' : 'left' : isFlip ? 'bottom' : 'top'}: -2px;
6901        padding: 1px;
6902        font-family: ui-monospace, monospace;
6903        font-size: 10px;
6904        letter-spacing: -.025em;
6905        line-height: 9px;
6906        font-weight: 600;
6907        text-align: ${isHori && isFlip || !isHori && !isView ? 'right' : 'left'};
6908        white-space: pre;
6909        text-overflow: ellipsis;
6910        color: ${isTail ? color : 'rgba(0,0,0,.75)'};
6911        background-color: ${isTail ? 'rgba(0,0,0,.65)' : color};
6912        border: 2px solid ${isTail ? color : 'transparent'};
6913        border-${isHori ? isFlip ? 'top-left' : 'top-right' : isFlip ? 'top-left' : 'bottom-left'}-radius: 5px;
6914        border-${isHori ? isFlip ? 'bottom-left' : 'bottom-right' : isFlip ? 'top-right' : 'bottom-right'}-radius: 5px;
6915      `;
6916        $label.appendChild($text);
6917        let position = value - flipOffset + (isHori ? 1 : 0);
6918        $label.style[isHori ? 'left' : 'top'] = `${position}px`;
6919        // $label.style[isHori ? 'left' : 'top'] = value - flipOffset + (!isFlip && isFirst && !isView ? 1 : isFlip ? 0 : -2) + 'px';
6920        (isView ? $thresholds : $triggers).appendChild($label);
6921      });
6922
6923      $debug.appendChild($thresholds);
6924      $debug.appendChild($triggers);
6925      container.element.appendChild($debug);
6926
6927      if (!$existingDebug) $debug.classList.add('animejs-onscroll-debug');
6928      this.$debug = $debug;
6929      const containerPosition = get(container.element, 'position');
6930      if (containerPosition === 'static') {
6931        this.debugStyles = set(container.element, { position: 'relative '});
6932      }
6933
6934    }
6935
6936    updateBounds() {
6937      if (this._debug) {
6938        this.removeDebug();
6939      }
6940      let stickys;
6941      const $target = this.target;
6942      const container = this.container;
6943      const isHori = this.horizontal;
6944      const linked = this.linked;
6945      let linkedTime;
6946      let $el = $target;
6947      // let offsetX = 0;
6948      // let offsetY = 0;
6949      // let $offsetParent = $el;
6950      
6950/** @type {Element} */
6951      if (linked) {
6952        linkedTime = linked.currentTime;
6953        linked.seek(0, true);
6954      }
6955      /*
vendor: 15,180 bytes, lines 6955-7408
6955 Old implementation to get offset and targetSize before fixing https://github.com/juliangarnier/anime/issues/1021
6956      // const isContainerStatic = get(container.element, 'position') === 'static' ? set(container.element, { position: 'relative '}) : false;
6957      // while ($el && $el !== container.element && $el !== doc.body) {
6958      //   const isSticky = get($el, 'position') === 'sticky' ?
6959      //                    set($el, { position: 'static' }) :
6960      //                    false;
6961      //   if ($el === $offsetParent) {
6962      //     offsetX += $el.offsetLeft || 0;
6963      //     offsetY += $el.offsetTop || 0;
6964      //     $offsetParent = $el.offsetParent;
6965      //   }
6966      //   $el = /** @type {HTMLElement} */($el.parentElement);
6967      //   if (isSticky) {
6968      //     if (!stickys) stickys = [];
6969      //     stickys.push(isSticky);
6970      //   }
6971      // }
6972      // if (isContainerStatic) isContainerStatic.revert();
6973      // const offset = isHori ? offsetX : offsetY;
6974      // const targetSize = isHori ? $target.offsetWidth : $target.offsetHeight;
6975
6976      while ($el && $el !== container.element && $el !== doc.body) {
6977        const isSticky = get($el, 'position') === 'sticky' ? set($el, { position: 'static' }) : false;
6978        $el = $el.parentElement;
6979        if (isSticky) {
6980          if (!stickys) stickys = [];
6981          stickys.push(isSticky);
6982        }
6983      }
6984      const rect = $target.getBoundingClientRect();
6985      const scale = container.scale;
6986      const offset = (isHori ? rect.left + container.scrollX - container.left : rect.top + container.scrollY - container.top) * scale;
6987      const targetSize = (isHori ? rect.width : rect.height) * scale;
6988      const containerSize = isHori ? container.width : container.height;
6989      const scrollSize = isHori ? container.scrollWidth : container.scrollHeight;
6990      const maxScroll = scrollSize - containerSize;
6991      const enter = this.enter;
6992      const leave = this.leave;
6993
6994      /** @type {ScrollThresholdValue} */
6995      let enterTarget = 'start';
6996      /** @type {ScrollThresholdValue} */
6997      let leaveTarget = 'end';
6998      /** @type {ScrollThresholdValue} */
6999      let enterContainer = 'end';
7000      /** @type {ScrollThresholdValue} */
7001      let leaveContainer = 'start';
7002
7003      if (isStr(enter)) {
7004        const splitted = /** @type {String} */(enter).split(' ');
7005        enterContainer = splitted[0];
7006        enterTarget = splitted.length > 1 ? splitted[1] : enterTarget;
7007      } else if (isObj(enter)) {
7008        const e = /** @type {ScrollThresholdParam} */(enter);
7009        if (!isUnd(e.container)) enterContainer = e.container;
7010        if (!isUnd(e.target)) enterTarget = e.target;
7011      } else if (isNum(enter)) {
7012        enterContainer = /** @type {Number} */(enter);
7013      }
7014
7015      if (isStr(leave)) {
7016        const splitted = /** @type {String} */(leave).split(' ');
7017        leaveContainer = splitted[0];
7018        leaveTarget = splitted.length > 1 ? splitted[1] : leaveTarget;
7019      } else if (isObj(leave)) {
7020        const t = /** @type {ScrollThresholdParam} */(leave);
7021        if (!isUnd(t.container)) leaveContainer = t.container;
7022        if (!isUnd(t.target)) leaveTarget = t.target;
7023      } else if (isNum(leave)) {
7024        leaveContainer = /** @type {Number} */(leave);
7025      }
7026
7027      const parsedEnterTarget = parseBoundValue($target, enterTarget, targetSize);
7028      const parsedLeaveTarget = parseBoundValue($target, leaveTarget, targetSize);
7029      const under = (parsedEnterTarget + offset) - containerSize;
7030      const over = (parsedLeaveTarget + offset) - maxScroll;
7031      const parsedEnterContainer = parseBoundValue($target, enterContainer, containerSize, under, over);
7032      const parsedLeaveContainer = parseBoundValue($target, leaveContainer, containerSize, under, over);
7033      const offsetStart = parsedEnterTarget + offset - parsedEnterContainer;
7034      const offsetEnd = parsedLeaveTarget + offset - parsedLeaveContainer;
7035      const scrollDelta = offsetEnd - offsetStart;
7036      this.offset = offset;
7037      this.offsetStart = offsetStart;
7038      this.offsetEnd = offsetEnd;
7039      this.distance = scrollDelta <= 0 ? 0 : scrollDelta;
7040      this.thresholds = [enterTarget, leaveTarget, enterContainer, leaveContainer];
7041      this.coords = [parsedEnterTarget, parsedLeaveTarget, parsedEnterContainer, parsedLeaveContainer];
7042      if (stickys) {
7043        stickys.forEach(sticky => sticky.revert());
7044      }
7045      if (linked) {
7046        linked.seek(linkedTime, true);
7047      }
7048      if (this._debug) {
7049        this.debug();
7050      }
7051    }
7052
7053    handleScroll() {
7054      if (!this.ready) return;
7055      const linked = this.linked;
7056      const sync = this.sync;
7057      const syncEase = this.syncEase;
7058      const syncSmooth = this.syncSmooth;
7059      const shouldSeek = linked && (syncEase || syncSmooth);
7060      const isHori = this.horizontal;
7061      const container = this.container;
7062      const scroll = this.scroll;
7063      const isBefore = scroll <= this.offsetStart;
7064      const isAfter = scroll >= this.offsetEnd;
7065      const isInView = !isBefore && !isAfter;
7066      const isOnTheEdge = scroll === this.offsetStart || scroll === this.offsetEnd;
7067      const forceEnter = !this.hasEntered && isOnTheEdge;
7068      const $debug = this._debug && this.$debug;
7069      let hasUpdated = false;
7070      let syncCompleted = false;
7071      let p = this.progress;
7072
7073      if (isBefore && this.began) {
7074        this.began = false;
7075      }
7076
7077      if (p > 0 && !this.began) {
7078        this.began = true;
7079      }
7080
7081      if (shouldSeek) {
7082        const lp = linked.progress;
7083        if (syncSmooth && isNum(syncSmooth)) {
7084          if (/** @type {Number} */(syncSmooth) < 1) {
7085            const step = 0.0001;
7086            const snap = lp < p && p === 1 ? step : lp > p && !p ? -step : 0;
7087            p = round$1(lerp$1(lp, p, lerp$1(.01, .2, /** @type {Number} */(syncSmooth))) + snap, 6);
7088          }
7089        } else if (syncEase) {
7090          p = syncEase(p);
7091        }
7092        hasUpdated = p !== this.prevProgress;
7093        syncCompleted = lp === 1;
7094        if (hasUpdated && !syncCompleted && (syncSmooth && lp)) {
7095          container.wakeTicker.restart();
7096        }
7097      }
7098
7099      if ($debug) {
7100        const sticky = isHori ? container.scrollY : container.scrollX;
7101        $debug.style[isHori ? 'top' : 'left'] = sticky + 10 + 'px';
7102      }
7103
7104      // Trigger enter callbacks if already in view or when entering the view
7105      if ((isInView && !this.isInView) || (forceEnter && !this.forceEnter && !this.hasEntered)) {
7106        if (isInView) this.isInView = true;
7107        if (!this.forceEnter || !this.hasEntered) {
7108          if ($debug && isInView) $debug.style.zIndex = `${this.container.zIndex++}`;
7109          this.onSyncEnter(this);
7110          this.onEnter(this);
7111          if (this.backward) {
7112            this.onSyncEnterBackward(this);
7113            this.onEnterBackward(this);
7114          } else {
7115            this.onSyncEnterForward(this);
7116            this.onEnterForward(this);
7117          }
7118          this.hasEntered = true;
7119          if (forceEnter) this.forceEnter = true;
7120        } else if (isInView) {
7121          this.forceEnter = false;
7122        }
7123      }
7124
7125      if (isInView || !isInView && this.isInView) {
7126        hasUpdated = true;
7127      }
7128
7129      if (hasUpdated) {
7130        if (shouldSeek) linked.seek(linked.duration * p);
7131        this.onUpdate(this);
7132      }
7133
7134      if (!isInView && this.isInView) {
7135        this.isInView = false;
7136        this.onSyncLeave(this);
7137        this.onLeave(this);
7138        if (this.backward) {
7139          this.onSyncLeaveBackward(this);
7140          this.onLeaveBackward(this);
7141        } else {
7142          this.onSyncLeaveForward(this);
7143          this.onLeaveForward(this);
7144        }
7145        if (sync && !syncSmooth) {
7146          syncCompleted = true;
7147        }
7148      }
7149
7150      if (p >= 1 && this.began && !this.completed && (sync && syncCompleted || !sync)) {
7151        if (sync) {
7152          this.onSyncComplete(this);
7153        }
7154        this.completed = true;
7155        if ((!this.repeat && !linked) || (!this.repeat && linked && linked.completed)) {
7156          this.revert();
7157        }
7158      }
7159
7160      if (p < 1 && this.completed) {
7161        this.completed = false;
7162      }
7163
7164      this.prevProgress = p;
7165    }
7166
7167    revert() {
7168      if (this.reverted) return;
7169      const container = this.container;
7170      removeChild(container, this);
7171      if (!container._head) {
7172        container.revert();
7173      }
7174      if (this._debug) {
7175        this.removeDebug();
7176      }
7177      this.reverted = true;
7178      this.ready = false;
7179      return this;
7180    }
7181
7182  }
7183
7184  /**
7185   * @param {ScrollObserverParams} [parameters={}]
7186   * @return {ScrollObserver}
7187   */
7188  const onScroll = (parameters = {}) => new ScrollObserver(parameters);
7189
7190  
7191
7192  /**
7193   * Cubic Bezier solver adapted from https://github.com/gre/bezier-easing
7194   * (c) 2014 Gaëtan Renaudeau
7195   */
7196
7197  /**
7198   * @param  {Number} aT
7199   * @param  {Number} aA1
7200   * @param  {Number} aA2
7201   * @return {Number}
7202   */
7203  const calcBezier = (aT, aA1, aA2) => (((1 - 3 * aA2 + 3 * aA1) * aT + (3 * aA2 - 6 * aA1)) * aT + (3 * aA1)) * aT;
7204
7205  /**
7206   * @param  {Number} aX
7207   * @param  {Number} mX1
7208   * @param  {Number} mX2
7209   * @return {Number}
7210   */
7211  const binarySubdivide = (aX, mX1, mX2) => {
7212    let aA = 0, aB = 1, currentX, currentT, i = 0;
7213    do {
7214      currentT = aA + (aB - aA) / 2;
7215      currentX = calcBezier(currentT, mX1, mX2) - aX;
7216      if (currentX > 0) {
7217        aB = currentT;
7218      } else {
7219        aA = currentT;
7220      }
7221    } while (abs(currentX) > .0000001 && ++i < 100);
7222    return currentT;
7223  };
7224
7225  /**
7226   * @param  {Number} [mX1] The x coordinate of the first point
7227   * @param  {Number} [mY1] The y coordinate of the first point
7228   * @param  {Number} [mX2] The x coordinate of the second point
7229   * @param  {Number} [mY2] The y coordinate of the second point
7230   * @return {EasingFunction}
7231   */
7232
7233  const cubicBezier = (mX1 = 0.5, mY1 = 0.0, mX2 = 0.5, mY2 = 1.0) => (mX1 === mY1 && mX2 === mY2) ? none :
7234    t => t === 0 || t === 1 ? t :
7235    calcBezier(binarySubdivide(t, mX1, mX2), mY1, mY2);
7236
7237  
7238
7239  /**
7240   * Steps ease implementation https://developer.mozilla.org/fr/docs/Web/CSS/transition-timing-function
7241   * Only covers 'end' and 'start' jumpterms
7242   * @param  {Number} steps
7243   * @param  {Boolean} [fromStart]
7244   * @return {EasingFunction}
7245   */
7246  const steps = (steps = 10, fromStart) => {
7247    const roundMethod = fromStart ? ceil : floor;
7248    return t => roundMethod(clamp$1(t, 0, 1) * steps) * (1 / steps);
7249  };
7250
7251  
7252
7253  /**
7254   * Without parameters, the linear function creates a non-eased transition.
7255   * Parameters, if used, creates a piecewise linear easing by interpolating linearly between the specified points.
7256   *
7257   * @param  {...(String|Number)} args - Points
7258   * @return {EasingFunction}
7259   */
7260  const linear = (...args) => {
7261    const argsLength = args.length;
7262    if (!argsLength) return none;
7263    const totalPoints = argsLength - 1;
7264    const firstArg = args[0];
7265    const lastArg = args[totalPoints];
7266    const xPoints = [0];
7267    const yPoints = [parseNumber(firstArg)];
7268    for (let i = 1; i < totalPoints; i++) {
7269      const arg = args[i];
7270      const splitValue = isStr(arg) ?
7271      /** @type {String} */(arg).trim().split(' ') :
7272      [arg];
7273      const value = splitValue[0];
7274      const percent = splitValue[1];
7275      xPoints.push(!isUnd(percent) ? parseNumber(percent) / 100 : i / totalPoints);
7276      yPoints.push(parseNumber(value));
7277    }
7278    yPoints.push(parseNumber(lastArg));
7279    xPoints.push(1);
7280    return function easeLinear(t) {
7281      for (let i = 1, l = xPoints.length; i < l; i++) {
7282        const currentX = xPoints[i];
7283        if (t <= currentX) {
7284          const prevX = xPoints[i - 1];
7285          const prevY = yPoints[i - 1];
7286          return prevY + (yPoints[i] - prevY) * (t - prevX) / (currentX - prevX);
7287        }
7288      }
7289      return yPoints[yPoints.length - 1];
7290    }
7291  };
7292
7293  
7294
7295  /**
7296   * Generate random steps
7297   * @param  {Number} [length] - The number of steps
7298   * @param  {Number} [randomness] - How strong the randomness is
7299   * @return {EasingFunction}
7300   */
7301  const irregular = (length = 10, randomness = 1) => {
7302    const values = [0];
7303    const total = length - 1;
7304    for (let i = 1; i < total; i++) {
7305      const previousValue = values[i - 1];
7306      const spacing = i / total;
7307      const segmentEnd = (i + 1) / total;
7308      const randomVariation = spacing + (segmentEnd - spacing) * Math.random();
7309      // Mix the even spacing and random variation based on the randomness parameter
7310      const randomValue = spacing * (1 - randomness) + randomVariation * randomness;
7311      values.push(clamp$1(randomValue, previousValue, 1));
7312    }
7313    values.push(1);
7314    return linear(...values);
7315  };
7316
7317  var index$3 = /*#__PURE__*/Object.freeze({
7318    __proto__: null,
7319    Spring: Spring,
7320    createSpring: createSpring,
7321    cubicBezier: cubicBezier,
7322    eases: eases,
7323    irregular: irregular,
7324    linear: linear,
7325    spring: spring,
7326    steps: steps
7327  });
7328
7329  
7330
7331  
7332
7333  
7334
7335  /**
7336   * Converts an easing function into a valid CSS linear() timing function string
7337   * @param {EasingFunction} fn
7338   * @param {number} [samples=100]
7339   * @returns {string} CSS linear() timing function
7340   */
7341  const easingToLinear = (fn, samples = 100) => {
7342    const points = [];
7343    for (let i = 0; i <= samples; i++) points.push(round$1(fn(i / samples), 4));
7344    return `linear(${points.join(', ')})`;
7345  };
7346
7347  const WAAPIEasesLookups = {};
7348
7349  /**
7350   * @param  {EasingParam} ease
7351   * @return {String}
7352   */
7353  const parseWAAPIEasing = (ease) => {
7354    let parsedEase = WAAPIEasesLookups[ease];
7355    if (parsedEase) return parsedEase;
7356    parsedEase = 'linear';
7357    if (isStr(ease)) {
7358      if (
7359        stringStartsWith(ease, 'linear') ||
7360        stringStartsWith(ease, 'cubic-') ||
7361        stringStartsWith(ease, 'steps') ||
7362        stringStartsWith(ease, 'ease')
7363      ) {
7364        parsedEase = ease;
7365      } else if (stringStartsWith(ease, 'cubicB')) {
7366        parsedEase = toLowerCase(ease);
7367      } else {
7368        const parsed = parseEaseString(ease);
7369        if (isFnc(parsed)) parsedEase = parsed === none ? 'linear' : easingToLinear(parsed);
7370      }
7371      // Only cache string based easing name, otherwise function arguments get lost
7372      WAAPIEasesLookups[ease] = parsedEase;
7373    } else if (isFnc(ease)) {
7374      const easing = easingToLinear(ease);
7375      if (easing) parsedEase = easing;
7376    } else if (/** @type {Spring} */(ease).ease) {
7377      parsedEase = easingToLinear(/** @type {Spring} */(ease).ease);
7378    }
7379    return parsedEase;
7380  };
7381
7382  const transformsShorthands = ['x', 'y', 'z'];
7383  const commonDefaultPXProperties = [
7384    'perspective',
7385    'width',
7386    'height',
7387    'margin',
7388    'padding',
7389    'top',
7390    'right',
7391    'bottom',
7392    'left',
7393    'borderWidth',
7394    'fontSize',
7395    'borderRadius',
7396    ...transformsShorthands
7397  ];
7398
7399  const validIndividualTransforms = /*#__PURE__*/ (() => [...transformsShorthands, ...validTransforms.filter(t => ['X', 'Y', 'Z'].some(axis => t.endsWith(axis)))])();
7400
7401  let transformsPropertiesRegistered = null;
7402
7403  /**
7404   * @param  {String} propName
7405   * @param  {WAAPIKeyframeValue} value
7406   * @param  {DOMTarget} $el
7407   * @param  {Number} i
7408   * @param  {
vendor: 9,429 bytes, lines 7408-7596
7408Number} targetsLength
7409   * @return {String}
7410   */
7411  const normalizeTweenValue = (propName, value, $el, i, targetsLength) => {
7412    // Do not try to compute strings with getFunctionValue otherwise it will convert CSS variables
7413    let v = isStr(value) ? value : getFunctionValue(/** @type {any} */(value), $el, i, targetsLength);
7414    if (!isNum(v)) return v;
7415    if (commonDefaultPXProperties.includes(propName) || stringStartsWith(propName, 'translate')) return `${v}px`;
7416    if (stringStartsWith(propName, 'rotate') || stringStartsWith(propName, 'skew')) return `${v}deg`;
7417    return `${v}`;
7418  };
7419
7420  /**
7421   * @param  {DOMTarget} $el
7422   * @param  {String} propName
7423   * @param  {WAAPIKeyframeValue} from
7424   * @param  {WAAPIKeyframeValue} to
7425   * @param  {Number} i
7426   * @param  {Number} targetsLength
7427   * @return {WAAPITweenValue}
7428   */
7429  const parseIndividualTweenValue = ($el, propName, from, to, i, targetsLength) => {
7430    /** @type {WAAPITweenValue} */
7431    let tweenValue = '0';
7432    const computedTo = !isUnd(to) ? normalizeTweenValue(propName, to, $el, i, targetsLength) : getComputedStyle($el)[propName];
7433    if (!isUnd(from)) {
7434      const computedFrom = normalizeTweenValue(propName, from, $el, i, targetsLength);
7435      tweenValue = [computedFrom, computedTo];
7436    } else {
7437      tweenValue = isArr(to) ? to.map((/** @type {any} */v) => normalizeTweenValue(propName, v, $el, i, targetsLength)) : computedTo;
7438    }
7439    return tweenValue;
7440  };
7441
7442  class WAAPIAnimation {
7443  /**
7444   * @param {DOMTargetsParam} targets
7445   * @param {WAAPIAnimationParams} params
7446   */
7447    constructor(targets, params) {
7448
7449      if (scope.current) scope.current.register(this);
7450
7451      // Skip the registration and fallback to no animation in case CSS.registerProperty is not supported
7452      if (isNil(transformsPropertiesRegistered)) {
7453        if (isBrowser && (isUnd(CSS) || !Object.hasOwnProperty.call(CSS, 'registerProperty'))) {
7454          transformsPropertiesRegistered = false;
7455        } else {
7456          validTransforms.forEach(t => {
7457            const isSkew = stringStartsWith(t, 'skew');
7458            const isScale = stringStartsWith(t, 'scale');
7459            const isRotate = stringStartsWith(t, 'rotate');
7460            const isTranslate = stringStartsWith(t, 'translate');
7461            const isAngle = isRotate || isSkew;
7462            const syntax = isAngle ? '<angle>' : isScale ? "<number>" : isTranslate ? "<length-percentage>" : "*";
7463            try {
7464              CSS.registerProperty({
7465                name: '--' + t,
7466                syntax,
7467                inherits: false,
7468                initialValue: isTranslate ? '0px' : isAngle ? '0deg' : isScale ? '1' : '0',
7469              });
7470            } catch {}        });
7471          transformsPropertiesRegistered = true;
7472        }
7473      }
7474
7475      const parsedTargets = registerTargets(targets);
7476      const targetsLength = parsedTargets.length;
7477
7478      if (!targetsLength) {
7479        console.warn(`No target found. Make sure the element you're trying to animate is accessible before creating your animation.`);
7480      }
7481
7482      const autoplay = setValue(params.autoplay, globals.defaults.autoplay);
7483      const scroll = autoplay && /** @type {ScrollObserver} */(autoplay).link ? autoplay : false;
7484      const alternate = params.alternate && /** @type {Boolean} */(params.alternate) === true;
7485      const reversed = params.reversed && /** @type {Boolean} */(params.reversed) === true;
7486      const loop = setValue(params.loop, globals.defaults.loop);
7487      const iterations = /** @type {Number} */((loop === true || loop === Infinity) ? Infinity : isNum(loop) ? loop + 1 : 1);
7488      /** @type {PlaybackDirection} */
7489      const direction = alternate ? reversed ? 'alternate-reverse' : 'alternate' : reversed ? 'reverse' : 'normal';
7490      /** @type {FillMode} */
7491      const fill = 'both'; // We use 'both' here because the animation can be reversed during playback
7492      const timeScale = (globals.timeScale === 1 ? 1 : K);
7493
7494      /** @type {DOMTargetsArray}] */
7495      this.targets = parsedTargets;
7496      /** @type {Array<globalThis.Animation>}] */
7497      this.animations = [];
7498      /** @type {globalThis.Animation}] */
7499      this.controlAnimation = null;
7500      /** @type {Callback<this>} */
7501      this.onComplete = params.onComplete || /** @type {Callback<WAAPIAnimation>} */(/** @type {unknown} */(globals.defaults.onComplete));
7502      /** @type {Number} */
7503      this.duration = 0;
7504      /** @type {Boolean} */
7505      this.muteCallbacks = false;
7506      /** @type {Boolean} */
7507      this.completed = false;
7508      /** @type {Boolean} */
7509      this.paused = !autoplay || scroll !== false;
7510      /** @type {Boolean} */
7511      this.reversed = reversed;
7512      /** @type {Boolean} */
7513      this.persist = setValue(params.persist, globals.defaults.persist);
7514      /** @type {Boolean|ScrollObserver} */
7515      this.autoplay = autoplay;
7516      /** @type {Number} */
7517      this._speed = setValue(params.playbackRate, globals.defaults.playbackRate);
7518      /** @type {Function} */
7519      this._resolve = noop; // Used by .then()
7520      /** @type {Number} */
7521      this._completed = 0;
7522      /** @type {Array.<Object>} */
7523      this._inlineStyles = [];
7524
7525      parsedTargets.forEach(($el, i) => {
7526
7527        const cachedTransforms = $el[transformsSymbol];
7528        const hasIndividualTransforms = validIndividualTransforms.some(t => params.hasOwnProperty(t));
7529        const elStyle = $el.style;
7530        const inlineStyles = this._inlineStyles[i] = {};
7531
7532        const easeToParse = setValue(params.ease, globals.defaults.ease);
7533
7534        const easeFunctionResult = getFunctionValue(easeToParse, $el, i, targetsLength);
7535        const keyEasing = isFnc(easeFunctionResult) || isStr(easeFunctionResult) ? easeFunctionResult : easeToParse;
7536
7537        const spring = /** @type {Spring} */(easeToParse).ease && easeToParse;
7538        /** @type {String} */
7539        const easing = parseWAAPIEasing(keyEasing);
7540
7541        /** @type {Number} */
7542        const duration = (spring ? /** @type {Spring} */(spring).settlingDuration : getFunctionValue(setValue(params.duration, globals.defaults.duration), $el, i, targetsLength)) * timeScale;
7543        /** @type {Number} */
7544        const delay = getFunctionValue(setValue(params.delay, globals.defaults.delay), $el, i, targetsLength) * timeScale;
7545        /** @type {CompositeOperation} */
7546        const composite = /** @type {CompositeOperation} */(setValue(params.composition, 'replace'));
7547
7548        for (let name in params) {
7549          if (!isKey(name)) continue;
7550          /** @type {PropertyIndexedKeyframes} */
7551          const keyframes = {};
7552          /** @type {KeyframeAnimationOptions} */
7553          const tweenParams = { iterations, direction, fill, easing, duration, delay, composite };
7554          const propertyValue = params[name];
7555          const individualTransformProperty = hasIndividualTransforms ? validTransforms.includes(name) ? name : shortTransforms.get(name) : false;
7556
7557          const styleName = individualTransformProperty ? 'transform' : name;
7558          if (!inlineStyles[styleName]) {
7559            inlineStyles[styleName] = elStyle[styleName];
7560          }
7561
7562          let parsedPropertyValue;
7563          if (isObj(propertyValue)) {
7564            const tweenOptions = /** @type {WAAPITweenOptions} */(propertyValue);
7565            const tweenOptionsEase = setValue(tweenOptions.ease, easing);
7566            const tweenOptionsSpring = /** @type {Spring} */(tweenOptionsEase).ease && tweenOptionsEase;
7567            const to = /** @type {WAAPITweenOptions} */(tweenOptions).to;
7568            const from = /** @type {WAAPITweenOptions} */(tweenOptions).from;
7569            /** @type {Number} */
7570            tweenParams.duration = (tweenOptionsSpring ? /** @type {Spring} */(tweenOptionsSpring).settlingDuration : getFunctionValue(setValue(tweenOptions.duration, duration), $el, i, targetsLength)) * timeScale;
7571            /** @type {Number} */
7572            tweenParams.delay = getFunctionValue(setValue(tweenOptions.delay, delay), $el, i, targetsLength) * timeScale;
7573            /** @type {CompositeOperation} */
7574            tweenParams.composite = /** @type {CompositeOperation} */(setValue(tweenOptions.composition, composite));
7575            /** @type {String} */
7576            tweenParams.easing = parseWAAPIEasing(tweenOptionsEase);
7577            parsedPropertyValue = parseIndividualTweenValue($el, name, from, to, i, targetsLength);
7578            if (individualTransformProperty) {
7579              keyframes[`--${individualTransformProperty}`] = parsedPropertyValue;
7580              cachedTransforms[individualTransformProperty] = parsedPropertyValue;
7581            } else {
7582              keyframes[name] = parseIndividualTweenValue($el, name, from, to, i, targetsLength);
7583            }
7584            addWAAPIAnimation(this, $el, name, keyframes, tweenParams);
7585            if (!isUnd(from)) {
7586              if (!individualTransformProperty) {
7587                elStyle[name] = keyframes[name][0];
7588              } else {
7589                const key = `--${individualTransformProperty}`;
7590                elStyle.setProperty(key, keyframes[key][0]);
7591              }
7592            }
7593          } else {
7594            parsedPropertyValue = isArr(propertyValue) ?
7595                                  propertyValue.map((/** @type {any} */v) => normalizeTweenValue(name, v, $el, i, targetsLength)) :
7596                                  normalizeTweenValue(name, /** @type {any} */(propertyValue), $el, i, targetsLength
vendor: 6,274 bytes, lines 7596-7806
7596);
7597            if (individualTransformProperty) {
7598              keyframes[`--${individualTransformProperty}`] = parsedPropertyValue;
7599              cachedTransforms[individualTransformProperty] = parsedPropertyValue;
7600            } else {
7601              keyframes[name] = parsedPropertyValue;
7602            }
7603            addWAAPIAnimation(this, $el, name, keyframes, tweenParams);
7604          }
7605        }
7606        if (hasIndividualTransforms) {
7607          let transforms = emptyString;
7608          for (let t in cachedTransforms) {
7609            transforms += `${transformsFragmentStrings[t]}var(--${t})) `;
7610          }
7611          elStyle.transform = transforms;
7612        }
7613      });
7614
7615      if (scroll) {
7616        /** @type {ScrollObserver} */(this.autoplay).link(this);
7617      }
7618    }
7619
7620    /**
7621     * @callback forEachCallback
7622     * @param {globalThis.Animation} animation
7623     */
7624
7625    /**
7626     * @param  {forEachCallback|String} callback
7627     * @return {this}
7628     */
7629    forEach(callback) {
7630      try {
7631        const cb = isStr(callback) ? (/** @type {globalThis.Animation} */a) => a[callback]() : callback;
7632        this.animations.forEach(cb);
7633      } catch {}    return this;
7634    }
7635
7636    get speed() {
7637      return this._speed;
7638    }
7639
7640    set speed(speed) {
7641      this._speed = +speed;
7642      this.forEach(anim => anim.playbackRate = speed);
7643    }
7644
7645    get currentTime() {
7646      const controlAnimation = this.controlAnimation;
7647      const timeScale = globals.timeScale;
7648      return this.completed ? this.duration : controlAnimation ? +controlAnimation.currentTime * (timeScale === 1 ? 1 : timeScale) : 0;
7649    }
7650
7651    set currentTime(time) {
7652      const t = time * (globals.timeScale === 1 ? 1 : K);
7653      this.forEach(anim => {
7654        // Make sure the animation playState is not 'paused' in order to properly trigger an onfinish callback.
7655        // 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.
7656        // https://developer.mozilla.org/en-US/docs/Web/API/Animation/finish_event
7657        // This is not needed for persisting animations since they never finish.
7658        if (!this.persist && t >= this.duration) anim.play();
7659        anim.currentTime = t;
7660      });
7661    }
7662
7663    get progress() {
7664      return this.currentTime / this.duration;
7665    }
7666
7667    set progress(progress) {
7668      this.forEach(anim => anim.currentTime = progress * this.duration || 0);
7669    }
7670
7671    resume() {
7672      if (!this.paused) return this;
7673      this.paused = false;
7674      // TODO: Store the current time, and seek back to the last position
7675      return this.forEach('play');
7676    }
7677
7678    pause() {
7679      if (this.paused) return this;
7680      this.paused = true;
7681      return this.forEach('pause');
7682    }
7683
7684    alternate() {
7685      this.reversed = !this.reversed;
7686      this.forEach('reverse');
7687      if (this.paused) this.forEach('pause');
7688      return this;
7689    }
7690
7691    play() {
7692      if (this.reversed) this.alternate();
7693      return this.resume();
7694    }
7695
7696    reverse() {
7697      if (!this.reversed) this.alternate();
7698      return this.resume();
7699    }
7700
7701   /**
7702    * @param {Number} time
7703    * @param {Boolean} muteCallbacks
7704    */
7705    seek(time, muteCallbacks = false) {
7706      if (muteCallbacks) this.muteCallbacks = true;
7707      if (time < this.duration) this.completed = false;
7708      this.currentTime = time;
7709      this.muteCallbacks = false;
7710      if (this.paused) this.pause();
7711      return this;
7712    }
7713
7714    restart() {
7715      this.completed = false;
7716      return this.seek(0, true).resume();
7717    }
7718
7719    commitStyles() {
7720      return this.forEach('commitStyles');
7721    }
7722
7723    complete() {
7724      return this.seek(this.duration);
7725    }
7726
7727    cancel() {
7728      this.muteCallbacks = true; // This prevents triggering the onComplete callback and resolving the Promise
7729      this.commitStyles().forEach('cancel');
7730      this.animations.length = 0; // Needed to release all animations from memory
7731      requestAnimationFrame(() => {
7732        this.targets.forEach(($el) => { // Needed to avoid unecessary inline transorms
7733          if ($el.style.transform === 'none') $el.style.removeProperty('transform');
7734        });
7735      });
7736      return this;
7737    }
7738
7739    revert() {
7740      // NOTE: We need a better way to revert the transforms, since right now the entire transform property value is reverted,
7741      // This means if you have multiple animations animating different transforms on the same target,
7742      // reverting one of them will also override the transform property of the other animations.
7743      // A better approach would be to store the original custom property values if they exist instead of the entire transform value,
7744      // and update the CSS variables with the orignal value
7745      this.cancel().targets.forEach(($el, i) => {
7746        const targetStyle = $el.style;
7747        const targetInlineStyles = this._inlineStyles[i];
7748        for (let name in targetInlineStyles) {
7749          const originalInlinedValue = targetInlineStyles[name];
7750          if (isUnd(originalInlinedValue) || originalInlinedValue === emptyString) {
7751            targetStyle.removeProperty(toLowerCase(name));
7752          } else {
7753            $el.style[name] = originalInlinedValue;
7754          }
7755        }
7756        // Remove style attribute if empty
7757        if ($el.getAttribute('style') === emptyString) $el.removeAttribute('style');
7758      });
7759      return this;
7760    }
7761
7762    /**
7763     * @typedef {this & {then: null}} ResolvedWAAPIAnimation
7764     */
7765
7766    /**
7767     * @param  {Callback<ResolvedWAAPIAnimation>} [callback]
7768     * @return Promise<this>
7769     */
7770    then(callback = noop) {
7771      const then = this.then;
7772      const onResolve = () => {
7773        this.then = null;
7774        callback(/** @type {ResolvedWAAPIAnimation} */(this));
7775        this.then = then;
7776        this._resolve = noop;
7777      };
7778      return new Promise(r => {
7779        this._resolve = () => r(onResolve());
7780        if (this.completed) this._resolve();
7781        return this;
7782      });
7783    }
7784  }
7785
7786  const waapi = {
7787  /**
7788   * @param {DOMTargetsParam} targets
7789   * @param {WAAPIAnimationParams} params
7790   * @return {WAAPIAnimation}
7791   */
7792    animate: (targets, params) => new WAAPIAnimation(targets, params),
7793    convertEase: easingToLinear
7794  };
7795
7796  
7797
7798  
7799
7800  
7801
7802  
7803
7804  
7805
7806  
7806/**
7807   * @typedef {DOMTargetSelector|Array<DOMTargetSelector>} LayoutChildrenParam
7808   */
7809
7810  /**
7811   * @typedef {Object} LayoutAnimationTimingsParams
7812   * @property {Number|FunctionValue} [delay]
7813   * @property {Number|FunctionValue} [duration]
7814   * @property {EasingParam|FunctionValue} [ease]
7815   */
7816
7817  /**
7818   * @typedef {Record<String, Number|String|FunctionValue>} LayoutStateAnimationProperties
7819   */
7820
7821  /**
7822   * @typedef {LayoutStateAnimationProperties & LayoutAnimationTimingsParams} LayoutStateParams
7823   */
7824
7825  /**
7826   * @typedef {Object} LayoutSpecificAnimationParams
7827   * @property {Number|FunctionValue} [delay]
7828   * @property {Number|FunctionValue} [duration]
7829   * @property {EasingParam|FunctionValue} [ease]
7830   * @property {EasingParam} [playbackEase]
7831   * @property {LayoutStateParams} [swapAt]
7832   * @property {LayoutStateParams} [enterFrom]
7833   * @property {LayoutStateParams} [leaveTo]
7834   */
7835
7836  /**
7837   * @typedef {LayoutSpecificAnimationParams & TimerParams & TickableCallbacks<Timeline> & RenderableCallbacks<Timeline>} LayoutAnimationParams
7838   */
7839
7840  /**
7841   * @typedef {Object} LayoutOptions
7842   * @property {LayoutChildrenParam} [children]
7843   * @property {Array<String>} [properties]
7844   */
7845
7846  /**
7847   * @typedef {LayoutAnimationParams & LayoutOptions} AutoLayoutParams
7848   */
7849
7850  /**
7851   * @typedef {Record<String, Number|String|FunctionValue> & {
7852   *   transform: String,
7853   *   x: Number,
7854   *   y: Number,
7855   *   left: Number,
7856   *   top: Number,
7857   *   clientLeft: Number,
7858   *   clientTop: Number,
7859   *   width: Number,
7860   *   height: Number,
7861   * }} LayoutNodeProperties
7862   */
7863
7864  /**
7865   * @typedef {Object} LayoutNode
7866   * @property {String} id
7867   * @property {DOMTarget} $el
7868   * @property {Number} index
7869   * @property {Number} total
7870   * @property {Number} delay
7871   * @property {Number} duration
7872   * @property {EasingParam} ease
7873   * @property {DOMTarget} $measure
7874   * @property {LayoutSnapshot} state
7875   * @property {AutoLayout} layout
7876   * @property {LayoutNode|null} parentNode
7877   * @property {Boolean} isTarget
7878   * @property {Boolean} isEntering
7879   * @property {Boolean} isLeaving
7880   * @property {Boolean} hasTransform
7881   * @property {Array<String>} inlineStyles
7882   * @property {String|null} inlineTransforms
7883   * @property {String|null} inlineTransition
7884   * @property {Boolean} branchAdded
7885   * @property {Boolean} branchRemoved
7886   * @property {Boolean} branchNotRendered
7887   * @property {Boolean} sizeChanged
7888   * @property {Boolean} isInlined
7889   * @property {Boolean} hasVisibilitySwap
7890   * @property {Boolean} hasDisplayNone
7891   * @property {Boolean} hasVisibilityHidden
7892   * @property {String|null} measuredInlineTransform
7893   * @property {String|null} measuredInlineTransition
7894   * @property {String|null} measuredDisplay
7895   * @property {String|null} measuredVisibility
7896   * @property {String|null} measuredPosition
7897   * @property {Boolean} measuredHasDisplayNone
7898   * @property {Boolean} measuredHasVisibilityHidden
7899   * @property {Boolean} measuredIsVisible
7900   * @property {Boolean} measuredIsRemoved
7901   * @property {Boolean} measuredIsInsideRoot
7902   * @property {LayoutNodeProperties} properties
7903   * @property {LayoutNode|null} _head
7904   * @property {LayoutNode|null} _tail
7905   * @property {LayoutNode|null} _prev
7906   * @property {LayoutNode|null} _next
7907   */
7908
7909  /**
7910   * @callback LayoutNodeIterator
7911   * @param {LayoutNode} node
7912   * @param {Number} index
7913   * @return {void}
7914   */
7915
7916  let layoutId = 0;
7917  let nodeId = 0;
7918
7919  /**
7920   * @param {DOMTarget} root
7921   * @param {DOMTarget} $el
7922   * @return {Boolean}
7923   */
7924  const isElementInRoot = (root, $el) => {
7925    if (!root || !$el) return false;
vendor: 2,430 bytes, lines 7926-8013
7926    return root === $el || root.contains($el);
7927  };
7928
7929  /**
7930   * @param {DOMTarget|null} $el
7931   * @return {String|null}
7932   */
7933  const muteElementTransition = $el => {
7934    if (!$el) return null;
7935    const style = $el.style;
7936    const transition = style.transition || '';
7937    style.setProperty('transition', 'none', 'important');
7938    return transition;
7939  };
7940
7941  /**
7942   * @param {DOMTarget|null} $el
7943   * @param {String|null} transition
7944   */
7945  const restoreElementTransition = ($el, transition) => {
7946    if (!$el) return;
7947    const style = $el.style;
7948    if (transition) {
7949      style.transition = transition;
7950    } else {
7951      style.removeProperty('transition');
7952    }
7953  };
7954
7955  /**
7956   * @param {LayoutNode} node
7957   */
7958  const muteNodeTransition = node => {
7959    const store = node.layout.transitionMuteStore;
7960    const $el = node.$el;
7961    const $measure = node.$measure;
7962    if ($el && !store.has($el)) store.set($el, muteElementTransition($el));
7963    if ($measure && !store.has($measure)) store.set($measure, muteElementTransition($measure));
7964  };
7965
7966  /**
7967   * @param {Map<DOMTarget, String|null>} store
7968   */
7969  const restoreLayoutTransition = store => {
7970    store.forEach((value, $el) => restoreElementTransition($el, value));
7971    store.clear();
7972  };
7973
7974  const hiddenComputedStyle = /** @type {CSSStyleDeclaration} */({
7975    display: 'none',
7976    visibility: 'hidden',
7977    opacity: '0',
7978    transform: 'none',
7979    position: 'static',
7980  });
7981
7982  /**
7983   * @param {LayoutNode|null} node
7984   */
7985  const detachNode = node => {
7986    if (!node) return;
7987    const parent = node.parentNode;
7988    if (!parent) return;
7989    if (parent._head === node) parent._head = node._next;
7990    if (parent._tail === node) parent._tail = node._prev;
7991    if (node._prev) node._prev._next = node._next;
7992    if (node._next) node._next._prev = node._prev;
7993    node._prev = null;
7994    node._next = null;
7995    node.parentNode = null;
7996  };
7997
7998  /**
7999   * @param {DOMTarget} $el
8000   * @param {LayoutNode|null} parentNode
8001   * @param {LayoutSnapshot} state
8002   * @param {LayoutNode} recycledNode
8003   * @return {LayoutNode}
8004   */
8005  const createNode = ($el, parentNode, state, recycledNode) => {
8006    let dataId = $el.dataset.layoutId;
8007    if (!dataId) dataId = $el.dataset.layoutId = `node-${nodeId++}`;
8008    const node = recycledNode ? recycledNode : /** @type {LayoutNode} */({});
8009    node.$el = $el;
8010    node.$measure = $el;
8011    node.id = dataId;
8012    node.index = 0;
8013    node.total = 1
vendor: 6,851 bytes, lines 8013-8199
8013;
8014    node.delay = 0;
8015    node.duration = 0;
8016    node.ease = null;
8017    node.state = state;
8018    node.layout = state.layout;
8019    node.parentNode = parentNode || null;
8020    node.isTarget = false;
8021    node.isEntering = false;
8022    node.isLeaving = false;
8023    node.isInlined = false;
8024    node.hasTransform = false;
8025    node.inlineStyles = [];
8026    node.inlineTransforms = null;
8027    node.inlineTransition = null;
8028    node.branchAdded = false;
8029    node.branchRemoved = false;
8030    node.branchNotRendered = false;
8031    node.sizeChanged = false;
8032    node.hasVisibilitySwap = false;
8033    node.hasDisplayNone = false;
8034    node.hasVisibilityHidden = false;
8035    node.measuredInlineTransform = null;
8036    node.measuredInlineTransition = null;
8037    node.measuredDisplay = null;
8038    node.measuredVisibility = null;
8039    node.measuredPosition = null;
8040    node.measuredHasDisplayNone = false;
8041    node.measuredHasVisibilityHidden = false;
8042    node.measuredIsVisible = false;
8043    node.measuredIsRemoved = false;
8044    node.measuredIsInsideRoot = false;
8045    node.properties = /** @type {LayoutNodeProperties} */({
8046      transform: 'none',
8047      x: 0,
8048      y: 0,
8049      left: 0,
8050      top: 0,
8051      clientLeft: 0,
8052      clientTop: 0,
8053      width: 0,
8054      height: 0,
8055    });
8056    node.layout.properties.forEach(prop => node.properties[prop] = 0);
8057    node._head = null;
8058    node._tail = null;
8059    node._prev = null;
8060    node._next = null;
8061    return node;
8062  };
8063
8064  /**
8065   * @param {LayoutNode} node
8066   * @param {DOMTarget} $measure
8067   * @param {CSSStyleDeclaration} computedStyle
8068   * @param {Boolean} skipMeasurements
8069   * @return {LayoutNode}
8070   */
8071  const recordNodeState = (node, $measure, computedStyle, skipMeasurements) => {
8072    const $el = node.$el;
8073    const root = node.layout.root;
8074    const isRoot = root === $el;
8075    const properties = node.properties;
8076    const rootNode = node.state.rootNode;
8077    const parentNode = node.parentNode;
8078    const computedTransforms = computedStyle.transform;
8079    const inlineTransforms = $el.style.transform;
8080    const parentNotRendered = parentNode ? parentNode.measuredIsRemoved : false;
8081    const position = computedStyle.position;
8082    if (isRoot) node.layout.absoluteCoords = position === 'fixed' || position === 'absolute';
8083    node.$measure = $measure;
8084    node.inlineTransforms = inlineTransforms;
8085    node.hasTransform = computedTransforms && computedTransforms !== 'none';
8086    node.measuredIsInsideRoot = isElementInRoot(root, $measure);
8087    node.measuredInlineTransform = null;
8088    node.measuredDisplay = computedStyle.display;
8089    node.measuredVisibility = computedStyle.visibility;
8090    node.measuredPosition = position;
8091    node.measuredHasDisplayNone = computedStyle.display === 'none';
8092    node.measuredHasVisibilityHidden = computedStyle.visibility === 'hidden';
8093    node.measuredIsVisible = !(node.measuredHasDisplayNone || node.measuredHasVisibilityHidden);
8094    node.measuredIsRemoved = node.measuredHasDisplayNone || node.measuredHasVisibilityHidden || parentNotRendered;
8095    // Check if element has adjacent text that would reflow when taken out of flow
8096    let hasAdjacentText = false;
8097    let s = $el.previousSibling;
8098    while (s && (s.nodeType === Node.COMMENT_NODE || (s.nodeType === Node.TEXT_NODE && !s.textContent.trim()))) s = s.previousSibling;
8099    if (s && s.nodeType === Node.TEXT_NODE) {
8100      hasAdjacentText = true;
8101    } else {
8102      s = $el.nextSibling;
8103      while (s && (s.nodeType === Node.COMMENT_NODE || (s.nodeType === Node.TEXT_NODE && !s.textContent.trim()))) s = s.nextSibling;
8104      hasAdjacentText = s !== null && s.nodeType === Node.TEXT_NODE;
8105    }
8106    node.isInlined = hasAdjacentText;
8107
8108    // Mute transforms (and transition to avoid triggering an animation) before the position calculation
8109    if (node.hasTransform && !skipMeasurements) {
8110      const transitionMuteStore = node.layout.transitionMuteStore;
8111      if (!transitionMuteStore.get($el)) node.inlineTransition = muteElementTransition($el);
8112      if ($measure === $el) {
8113        $el.style.transform = 'none';
8114      } else {
8115        if (!transitionMuteStore.get($measure)) node.measuredInlineTransition = muteElementTransition($measure);
8116        node.measuredInlineTransform = $measure.style.transform;
8117        $measure.style.transform = 'none';
8118      }
8119    }
8120
8121    let left = 0;
8122    let top = 0;
8123    let width = 0;
8124    let height = 0;
8125
8126    if (!skipMeasurements) {
8127      const rect = $measure.getBoundingClientRect();
8128      left = rect.left;
8129      top = rect.top;
8130      width = rect.width;
8131      height = rect.height;
8132    }
8133
8134    for (let name in properties) {
8135      const computedProp = name === 'transform' ? computedTransforms : computedStyle[name] || (computedStyle.getPropertyValue && computedStyle.getPropertyValue(name));
8136      if (!isUnd(computedProp)) properties[name] = computedProp;
8137    }
8138
8139    properties.left = left;
8140    properties.top = top;
8141    properties.clientLeft = skipMeasurements ? 0 : $measure.clientLeft;
8142    properties.clientTop = skipMeasurements ? 0 : $measure.clientTop;
8143    // Compute local x/y relative to parent
8144    let absoluteLeft, absoluteTop;
8145    if (isRoot) {
8146      if (!node.layout.absoluteCoords) {
8147        absoluteLeft = 0;
8148        absoluteTop = 0;
8149      } else {
8150        absoluteLeft = left;
8151        absoluteTop = top;
8152      }
8153    } else {
8154      const p = parentNode || rootNode;
8155      const parentLeft = p.properties.left;
8156      const parentTop = p.properties.top;
8157      const borderLeft = p.properties.clientLeft;
8158      const borderTop = p.properties.clientTop;
8159      if (!node.layout.absoluteCoords) {
8160        if (p === rootNode) {
8161          const rootLeft = rootNode.properties.left;
8162          const rootTop = rootNode.properties.top;
8163          const rootBorderLeft = rootNode.properties.clientLeft;
8164          const rootBorderTop = rootNode.properties.clientTop;
8165          absoluteLeft = left - rootLeft - rootBorderLeft;
8166          absoluteTop = top - rootTop - rootBorderTop;
8167        } else {
8168          absoluteLeft = left - parentLeft - borderLeft;
8169          absoluteTop = top - parentTop - borderTop;
8170        }
8171      } else {
8172        absoluteLeft = left - parentLeft - borderLeft;
8173        absoluteTop = top - parentTop - borderTop;
8174      }
8175    }
8176    properties.x = absoluteLeft;
8177    properties.y = absoluteTop;
8178    properties.width = width;
8179    properties.height = height;
8180    return node;
8181  };
8182
8183  /**
8184   * @param {LayoutNode} node
8185   * @param {LayoutStateAnimationProperties} [props]
8186   */
8187  const updateNodeProperties = (node, props) => {
8188    if (!props) return;
8189    for (let name in props) {
8190      node.properties[name] = props[name];
8191    }
8192  };
8193
8194  /**
8195   * @param  {LayoutNode} node
8196   * @param  {LayoutAnimationTimingsParams} params
8197   */
8198  const updateNodeTimingParams = (node, params) => {
8199    const easeFunctionResult = getFunctionValue(params.ease, node.$el, node.index, node.t
8199otal);
8200    const keyEasing = isFnc(easeFunctionResult) ? easeFunctionResult : params.ease;
8201    const hasSpring = !isUnd(keyEasing) && !isUnd(/** @type {Spring} */(keyEasing).ease);
8202    node.ease = hasSpring ? /** @type {Spring} */(keyEasing).ease : keyEasing;
8203    node.duration = hasSpring ? /** @type {Spring} */(keyEasing).settlingDuration : getFunctionValue(params.duration, node.$el, node.index, node.total);
8204    node.delay = getFunctionValue(params.delay, node.$el, node.index, node.tota
vendor: 12,531 bytes, lines 8204-8577
8204l);
8205  };
8206
8207  /**
8208   * @param {LayoutNode} node
8209   */
8210  const recordNodeInlineStyles = node => {
8211    const style = node.$el.style;
8212    const stylesStore = node.inlineStyles;
8213    stylesStore.length = 0;
8214    node.layout.recordedProperties.forEach(prop => {
8215      stylesStore.push(prop, style[prop] || '');
8216    });
8217  };
8218
8219  /**
8220   * @param {LayoutNode} node
8221   */
8222  const restoreNodeInlineStyles = node => {
8223    const style = node.$el.style;
8224    const stylesStore = node.inlineStyles;
8225    for (let i = 0, l = stylesStore.length; i < l; i += 2) {
8226      const property = stylesStore[i];
8227      const styleValue = stylesStore[i + 1];
8228      if (styleValue && styleValue !== '') {
8229        style[property] = styleValue;
8230      } else {
8231        style[property] = '';
8232        style.removeProperty(property);
8233      }
8234    }
8235  };
8236
8237  /**
8238   * @param {LayoutNode} node
8239   */
8240  const restoreNodeTransform = node => {
8241    const inlineTransforms = node.inlineTransforms;
8242    const nodeStyle = node.$el.style;
8243    if (!node.hasTransform || !inlineTransforms || (node.hasTransform && nodeStyle.transform === 'none') || (inlineTransforms && inlineTransforms === 'none')) {
8244      nodeStyle.removeProperty('transform');
8245    } else if (inlineTransforms) {
8246      nodeStyle.transform = inlineTransforms;
8247    }
8248    const $measure = node.$measure;
8249    if (node.hasTransform && $measure !== node.$el) {
8250      const measuredStyle = $measure.style;
8251      const measuredInline = node.measuredInlineTransform;
8252      if (measuredInline && measuredInline !== '') {
8253        measuredStyle.transform = measuredInline;
8254      } else {
8255        measuredStyle.removeProperty('transform');
8256      }
8257    }
8258    node.measuredInlineTransform = null;
8259    if (node.inlineTransition !== null) {
8260      restoreElementTransition(node.$el, node.inlineTransition);
8261      node.inlineTransition = null;
8262    }
8263    if ($measure !== node.$el && node.measuredInlineTransition !== null) {
8264      restoreElementTransition($measure, node.measuredInlineTransition);
8265      node.measuredInlineTransition = null;
8266    }
8267  };
8268
8269  /**
8270   * @param {LayoutNode} node
8271   */
8272  const restoreNodeVisualState = node => {
8273    if (node.measuredIsRemoved || node.hasVisibilitySwap) {
8274      node.$el.style.removeProperty('display');
8275      node.$el.style.removeProperty('visibility');
8276      if (node.hasVisibilitySwap) {
8277        node.$measure.style.removeProperty('display');
8278        node.$measure.style.removeProperty('visibility');
8279      }
8280    }
8281    // if (node.measuredIsRemoved) {
8282    node.layout.pendingRemoval.delete(node.$el);
8283    // }
8284  };
8285
8286  /**
8287   * @param {LayoutNode} node
8288   * @param {LayoutNode} targetNode
8289   * @param {LayoutSnapshot} newState
8290   * @return {LayoutNode}
8291   */
8292  const cloneNodeProperties = (node, targetNode, newState) => {
8293    targetNode.properties = /** @type {LayoutNodeProperties} */({ ...node.properties });
8294    targetNode.state = newState;
8295    targetNode.isTarget = node.isTarget;
8296    targetNode.hasTransform = node.hasTransform;
8297    targetNode.inlineTransforms = node.inlineTransforms;
8298    targetNode.measuredIsVisible = node.measuredIsVisible;
8299    targetNode.measuredDisplay = node.measuredDisplay;
8300    targetNode.measuredIsRemoved = node.measuredIsRemoved;
8301    targetNode.measuredHasDisplayNone = node.measuredHasDisplayNone;
8302    targetNode.measuredHasVisibilityHidden = node.measuredHasVisibilityHidden;
8303    targetNode.hasDisplayNone = node.hasDisplayNone;
8304    targetNode.isInlined = node.isInlined;
8305    targetNode.hasVisibilityHidden = node.hasVisibilityHidden;
8306    return targetNode;
8307  };
8308
8309  class LayoutSnapshot {
8310    /**
8311     * @param {AutoLayout} layout
8312     */
8313    constructor(layout) {
8314      /** @type {AutoLayout} */
8315      this.layout = layout;
8316      /** @type {LayoutNode|null} */
8317      this.rootNode = null;
8318      /** @type {Set<LayoutNode>} */
8319      this.rootNodes = new Set();
8320      /** @type {Map<String, LayoutNode>} */
8321      this.nodes = new Map();
8322      /** @type {Number} */
8323      this.scrollX = 0;
8324      /** @type {Number} */
8325      this.scrollY = 0;
8326    }
8327
8328    /**
8329     * @return {this}
8330     */
8331    revert() {
8332      this.forEachNode(node => {
8333        this.layout.pendingRemoval.delete(node.$el);
8334        node.$el.removeAttribute('data-layout-id');
8335        node.$measure.removeAttribute('data-layout-id');
8336      });
8337      this.rootNode = null;
8338      this.rootNodes.clear();
8339      this.nodes.clear();
8340      return this;
8341    }
8342
8343    /**
8344     * @param {DOMTarget} $el
8345     * @return {LayoutNode}
8346     */
8347    getNode($el) {
8348      if (!$el || !$el.dataset) return;
8349      return this.nodes.get($el.dataset.layoutId);
8350    }
8351
8352    /**
8353     * @param {DOMTarget} $el
8354     * @param {String} prop
8355     * @return {Number|String}
8356     */
8357    getComputedValue($el, prop) {
8358      const node = this.getNode($el);
8359      if (!node) return;
8360      return /** @type {Number|String} */(node.properties[prop]);
8361    }
8362
8363    /**
8364     * @param {LayoutNode|null} rootNode
8365     * @param {LayoutNodeIterator} cb
8366     */
8367    forEach(rootNode, cb) {
8368      let node = rootNode;
8369      let i = 0;
8370      while (node) {
8371        cb(node, i++);
8372        if (node._head) {
8373          node = node._head;
8374        } else if (node._next) {
8375          node = node._next;
8376        } else {
8377          while (node && !node._next) {
8378            node = node.parentNode;
8379          }
8380          if (node) node = node._next;
8381        }
8382      }
8383    }
8384
8385    /**
8386     * @param {LayoutNodeIterator} cb
8387     */
8388    forEachRootNode(cb) {
8389      this.forEach(this.rootNode, cb);
8390    }
8391
8392    /**
8393     * @param {LayoutNodeIterator} cb
8394     */
8395    forEachNode(cb) {
8396      for (const rootNode of this.rootNodes) {
8397        this.forEach(rootNode, cb);
8398      }
8399    }
8400
8401    /**
8402     * @param {DOMTarget} $el
8403     * @param {LayoutNode|null} parentNode
8404     * @return {LayoutNode|null}
8405     */
8406    registerElement($el, parentNode) {
8407      if (!$el || $el.nodeType !== 1) return null;
8408
8409      if (!this.layout.transitionMuteStore.has($el)) this.layout.transitionMuteStore.set($el, muteElementTransition($el));
8410
8411      /** @type {Array<DOMTarget|LayoutNode|null>} */
8412      const stack = [$el, parentNode];
8413      const root = this.layout.root;
8414      let firstNode = null;
8415
8416      while (stack.length) {
8417        /** @type {LayoutNode|null} */
8418        const $parent = /** @type {LayoutNode|null} */(stack.pop());
8419        /** @type {DOMTarget|null} */
8420        const $current = /** @type {DOMTarget|null} */(stack.pop());
8421
8422        if (!$current || $current.nodeType !== 1 || isSvg($current)) continue;
8423
8424        const skipMeasurements = $parent ? $parent.measuredIsRemoved : false;
8425        const computedStyle = skipMeasurements ? hiddenComputedStyle : getComputedStyle($current);
8426        const hasDisplayNone = skipMeasurements ? true : computedStyle.display === 'none';
8427        const hasVisibilityHidden = skipMeasurements ? true : computedStyle.visibility === 'hidden';
8428        const isVisible = !hasDisplayNone && !hasVisibilityHidden;
8429        const existingId = $current.dataset.layoutId;
8430        const isInsideRoot = isElementInRoot(root, $current);
8431
8432        let node = existingId ? this.nodes.get(existingId) : null;
8433
8434        if (node && node.$el !== $current) {
8435          const nodeInsideRoot = isElementInRoot(root, node.$el);
8436          const measuredVisible = node.measuredIsVisible;
8437          const shouldReassignNode = !nodeInsideRoot && (isInsideRoot || (!isInsideRoot && !measuredVisible && isVisible));
8438          const shouldReuseMeasurements = nodeInsideRoot && !measuredVisible && isVisible;
8439          // Rebind nodes that move into the root or whose detached twin just became visible
8440          if (shouldReassignNode) {
8441            detachNode(node);
8442            node = createNode($current, $parent, this, node);
8443          // for hidden element with in-root sibling, keep the hidden node but borrow measurements from its visible in-root twin element
8444          } else if (shouldReuseMeasurements) {
8445            recordNodeState(node, $current, computedStyle, skipMeasurements);
8446            let $child = $current.lastElementChild;
8447            while ($child) {
8448              stack.push(/** @type {DOMTarget} */($child), node);
8449              $child = $child.previousElementSibling;
8450            }
8451            if (!firstNode) firstNode = node;
8452            continue;
8453          // No reassignment needed so keep walking descendants under the current parent
8454          } else {
8455            let $child = $current.lastElementChild;
8456            while ($child) {
8457              stack.push(/** @type {DOMTarget} */($child), $parent);
8458              $child = $child.previousElementSibling;
8459            }
8460            if (!firstNode) firstNode = node;
8461            continue;
8462          }
8463        } else {
8464          node = createNode($current, $parent, this, node);
8465        }
8466
8467        node.branchAdded = false;
8468        node.branchRemoved = false;
8469        node.branchNotRendered = false;
8470        node.isTarget = false;
8471        node.sizeChanged = false;
8472        node.hasVisibilityHidden = hasVisibilityHidden;
8473        node.hasDisplayNone = hasDisplayNone;
8474        node.hasVisibilitySwap = (hasVisibilityHidden && !node.measuredHasVisibilityHidden) || (hasDisplayNone && !node.measuredHasDisplayNone);
8475
8476        this.nodes.set(node.id, node);
8477
8478        node.parentNode = $parent || null;
8479        node._prev = null;
8480        node._next = null;
8481
8482        if ($parent) {
8483          this.rootNodes.delete(node);
8484          if (!$parent._head) {
8485            $parent._head = node;
8486            $parent._tail = node;
8487          } else {
8488            $parent._tail._next = node;
8489            node._prev = $parent._tail;
8490            $parent._tail = node;
8491          }
8492        } else {
8493          // Each disconnected subtree becomes its own root in the snapshot graph
8494          this.rootNodes.add(node);
8495        }
8496
8497        recordNodeState(node, node.$el, computedStyle, skipMeasurements);
8498
8499        let $child = $current.lastElementChild;
8500        while ($child) {
8501          stack.push(/** @type {DOMTarget} */($child), node);
8502          $child = $child.previousElementSibling;
8503        }
8504
8505        if (!firstNode) firstNode = node;
8506      }
8507
8508      return firstNode;
8509    }
8510
8511    /**
8512     * @param {DOMTarget} $el
8513     * @param {Set<DOMTarget>} candidates
8514     * @return {LayoutNode|null}
8515     */
8516    ensureDetachedNode($el, candidates) {
8517      if (!$el || $el === this.layout.root) return null;
8518      const existingId = $el.dataset.layoutId;
8519      const existingNode = existingId ? this.nodes.get(existingId) : null;
8520      if (existingNode && existingNode.$el === $el) return existingNode;
8521      let parentNode = null;
8522      let $ancestor = $el.parentElement;
8523      while ($ancestor && $ancestor !== this.layout.root) {
8524        if (candidates.has($ancestor)) {
8525          parentNode = this.ensureDetachedNode($ancestor, candidates);
8526          break;
8527        }
8528        $ancestor = $ancestor.parentElement;
8529      }
8530      return this.registerElement($el, parentNode);
8531    }
8532
8533    /**
8534     * @return {this}
8535     */
8536    record() {
8537      const layout = this.layout;
8538      const children = layout.children;
8539      const root = layout.root;
8540      const toParse = isArr(children) ? children : [children];
8541      const scoped = [];
8542      const scopeRoot = children === '*' ? root : scope.root;
8543
8544      // Mute transition and transforms of root ancestors before recording the state
8545
8546      /** @type {Array<DOMTarget|String|null>} */
8547      const rootAncestorTransformStore = [];
8548      let $ancestor = root.parentElement;
8549      while ($ancestor && $ancestor.nodeType === 1) {
8550        const computedStyle = getComputedStyle($ancestor);
8551        if (computedStyle.transform && computedStyle.transform !== 'none') {
8552          const inlineTransform = $ancestor.style.transform || '';
8553          const inlineTransition = muteElementTransition($ancestor);
8554          rootAncestorTransformStore.push($ancestor, inlineTransform, inlineTransition);
8555          $ancestor.style.transform = 'none';
8556        }
8557        $ancestor = $ancestor.parentElement;
8558      }
8559
8560      for (let i = 0, l = toParse.length; i < l; i++) {
8561        const child = toParse[i];
8562        scoped[i] = isStr(child) ? scopeRoot.querySelectorAll(child) : child;
8563      }
8564
8565      const parsedChildren = registerTargets(scoped);
8566
8567      this.nodes.clear();
8568      this.rootNodes.clear();
8569
8570      const rootNode = this.registerElement(root, null);
8571      // Root node are always targets
8572      rootNode.isTarget = true;
8573      this.rootNode = rootNode;
8574
8575      const inRootNodeIds = new Set();
8576      // Update index and total for inital timing calculation
8577      let index = 0
8577, total = this.nodes.size;
vendor: 40,764 bytes, lines 8578-9603
8578      this.nodes.forEach((node, id) => {
8579        node.index = index++;
8580        node.total = total;
8581        // Track ids of nodes that belong to the current root to filter detached matches
8582        if (node && node.measuredIsInsideRoot) {
8583          inRootNodeIds.add(id);
8584        }
8585      });
8586
8587      // Elements with a layout id outside the root that match the children selector
8588      const detachedElementsLookup = new Set();
8589      const orderedDetachedElements = [];
8590
8591      for (let i = 0, l = parsedChildren.length; i < l; i++) {
8592        const $el = parsedChildren[i];
8593        if (!$el || $el.nodeType !== 1 || $el === root) continue;
8594        const insideRoot = isElementInRoot(root, $el);
8595        if (!insideRoot) {
8596          const layoutNodeId = $el.dataset.layoutId;
8597          if (!layoutNodeId || !inRootNodeIds.has(layoutNodeId)) continue;
8598        }
8599        if (!detachedElementsLookup.has($el)) {
8600          detachedElementsLookup.add($el);
8601          orderedDetachedElements.push($el);
8602        }
8603      }
8604
8605      for (let i = 0, l = orderedDetachedElements.length; i < l; i++) {
8606        this.ensureDetachedNode(orderedDetachedElements[i], detachedElementsLookup);
8607      }
8608
8609      for (let i = 0, l = parsedChildren.length; i < l; i++) {
8610        const $el = parsedChildren[i];
8611        const node = this.getNode($el);
8612        if (node) {
8613          let cur = node;
8614          while (cur) {
8615            if (cur.isTarget) break;
8616            cur.isTarget = true;
8617            cur = cur.parentNode;
8618          }
8619        }
8620      }
8621
8622      this.scrollX = window.scrollX;
8623      this.scrollY = window.scrollY;
8624
8625      this.forEachNode(restoreNodeTransform);
8626
8627      // Restore transition and transforms of root ancestors
8628
8629      for (let i = 0, l = rootAncestorTransformStore.length; i < l; i += 3) {
8630        const $el = /** @type {DOMTarget} */(rootAncestorTransformStore[i]);
8631        const inlineTransform = /** @type {String} */(rootAncestorTransformStore[i + 1]);
8632        const inlineTransition = /** @type {String|null} */(rootAncestorTransformStore[i + 2]);
8633        if (inlineTransform && inlineTransform !== '') {
8634          $el.style.transform = inlineTransform;
8635        } else {
8636          $el.style.removeProperty('transform');
8637        }
8638        restoreElementTransition($el, inlineTransition);
8639      }
8640
8641      return this;
8642    }
8643  }
8644
8645  /**
8646   * @param  {LayoutStateParams} params
8647   * @return {[LayoutStateAnimationProperties, LayoutAnimationTimingsParams]}
8648   */
8649  function splitPropertiesFromParams(params) {
8650    /** @type {LayoutStateAnimationProperties} */
8651    const properties = {};
8652    /** @type {LayoutAnimationTimingsParams} */
8653    const parameters = {};
8654    for (let name in params) {
8655      const value = params[name];
8656      const isEase = name === 'ease';
8657      const isTiming = name === 'duration' || name === 'delay';
8658      if (isTiming || isEase) {
8659        if (isEase) {
8660          parameters[name] = /** @type {EasingParam} */(value);
8661        } else {
8662          parameters[name] = /** @type {Number|FunctionValue} */(value);
8663        }
8664      } else {
8665        properties[name] = /** @type {Number|String} */(value);
8666      }
8667    }
8668    return [properties, parameters];
8669  }
8670
8671  class AutoLayout {
8672    /**
8673     * @param {DOMTargetSelector} root
8674     * @param {AutoLayoutParams} [params]
8675     */
8676    constructor(root, params = {}) {
8677      if (scope.current) scope.current.register(this);
8678      const swapAtSplitParams = splitPropertiesFromParams(params.swapAt);
8679      const enterFromSplitParams = splitPropertiesFromParams(params.enterFrom);
8680      const leaveToSplitParams = splitPropertiesFromParams(params.leaveTo);
8681      const transitionProperties = params.properties;
8682      /** @type {Number|FunctionValue} */
8683      params.duration = setValue(params.duration, 350);
8684      /** @type {Number|FunctionValue} */
8685      params.delay = setValue(params.delay, 0);
8686      /** @type {EasingParam|FunctionValue} */
8687      params.ease = setValue(params.ease, 'inOut(3.5)');
8688      /** @type {AutoLayoutParams} */
8689      this.params = params;
8690      /** @type {DOMTarget} */
8691      this.root = /** @type {DOMTarget} */(registerTargets(root)[0]);
8692      /** @type {Number} */
8693      this.id = layoutId++;
8694      /** @type {LayoutChildrenParam} */
8695      this.children = params.children || '*';
8696      /** @type {Boolean} */
8697      this.absoluteCoords = false;
8698      /** @type {LayoutStateParams} */
8699      this.swapAtParams = mergeObjects(params.swapAt || { opacity: 0 }, { ease: 'inOut(1.75)' });
8700      /** @type {LayoutStateParams} */
8701      this.enterFromParams = params.enterFrom || { opacity: 0 };
8702      /** @type {LayoutStateParams} */
8703      this.leaveToParams = params.leaveTo || { opacity: 0 };
8704      /** @type {Set<String>} */
8705      this.properties = new Set([
8706        'opacity',
8707        'fontSize',
8708        'color',
8709        'backgroundColor',
8710        'borderRadius',
8711        'border',
8712        'filter',
8713        'clipPath',
8714      ]);
8715      if (swapAtSplitParams[0]) for (let name in swapAtSplitParams[0]) this.properties.add(name);
8716      if (enterFromSplitParams[0]) for (let name in enterFromSplitParams[0]) this.properties.add(name);
8717      if (leaveToSplitParams[0]) for (let name in leaveToSplitParams[0]) this.properties.add(name);
8718      if (transitionProperties) for (let i = 0, l = transitionProperties.length; i < l; i++) this.properties.add(transitionProperties[i]);
8719      /** @type {Set<String>} */
8720      this.recordedProperties = new Set([
8721        'display',
8722        'visibility',
8723        'translate',
8724        'position',
8725        'left',
8726        'top',
8727        'marginLeft',
8728        'marginTop',
8729        'width',
8730        'height',
8731        'maxWidth',
8732        'maxHeight',
8733        'minWidth',
8734        'minHeight',
8735      ]);
8736      this.properties.forEach(prop => this.recordedProperties.add(prop));
8737      /** @type {WeakSet<DOMTarget>} */
8738      this.pendingRemoval = new WeakSet();
8739      /** @type {Map<DOMTarget, String|null>} */
8740      this.transitionMuteStore = new Map();
8741      /** @type {LayoutSnapshot} */
8742      this.oldState = new LayoutSnapshot(this);
8743      /** @type {LayoutSnapshot} */
8744      this.newState = new LayoutSnapshot(this);
8745      /** @type {Timeline} */
8746      this.timeline = null;
8747      /** @type {WAAPIAnimation} */
8748      this.transformAnimation = null;
8749      /** @type {Array<DOMTarget>} */
8750      this.animating = [];
8751      /** @type {Array<DOMTarget>} */
8752      this.swapping = [];
8753      /** @type {Array<DOMTarget>} */
8754      this.leaving = [];
8755      /** @type {Array<DOMTarget>} */
8756      this.entering = [];
8757      // Record the current state as the old state to init the data attributes and allow imediate .animate()
8758      this.oldState.record();
8759      // And all layout transition muted during the record
8760      restoreLayoutTransition(this.transitionMuteStore);
8761    }
8762
8763    /**
8764     * @return {this}
8765     */
8766    revert() {
8767      this.root.classList.remove('is-animated');
8768      if (this.timeline) {
8769        this.timeline.complete();
8770        this.timeline = null;
8771      }
8772      if (this.transformAnimation) {
8773        this.transformAnimation.complete();
8774        this.transformAnimation = null;
8775      }
8776      this.animating.length = this.swapping.length = this.leaving.length = this.entering.length = 0;
8777      this.oldState.revert();
8778      this.newState.revert();
8779      requestAnimationFrame(() => restoreLayoutTransition(this.transitionMuteStore));
8780      return this;
8781    }
8782
8783    /**
8784     * @return {this}
8785     */
8786    record() {
8787      // Commit transforms before measuring
8788      if (this.transformAnimation) {
8789        this.transformAnimation.cancel();
8790        this.transformAnimation = null;
8791      }
8792      // Record the old state
8793      this.oldState.record();
8794      // Cancel any running timeline
8795      if (this.timeline) {
8796        this.timeline.cancel();
8797        this.timeline = null;
8798      }
8799      // Restore previously captured inline styles
8800      this.newState.forEachRootNode(restoreNodeInlineStyles);
8801      return this;
8802    }
8803
8804    /**
8805     * @param {LayoutAnimationParams} [params]
8806     * @return {Timeline}
8807     */
8808    animate(params = {}) {
8809      /** @type { LayoutAnimationTimingsParams } */
8810      const animationTimings = {
8811        ease: setValue(params.ease, this.params.ease),
8812        delay: setValue(params.delay, this.params.delay),
8813        duration: setValue(params.duration, this.params.duration),
8814      };
8815      /** @type {TimelineParams} */
8816      const tlParams = {};
8817      const onComplete = setValue(params.onComplete, this.params.onComplete);
8818      const onPause = setValue(params.onPause, this.params.onPause);
8819      for (let name in defaults) {
8820        if (name !== 'ease' && name !== 'duration' && name !== 'delay') {
8821          if (!isUnd(params[name])) {
8822            tlParams[name] = params[name];
8823          } else if (!isUnd(this.params[name])) {
8824            tlParams[name] = this.params[name];
8825          }
8826        }
8827      }
8828      tlParams.onComplete = () => {
8829        // Make sure to call .cancel() after restoreNodeInlineStyles(node); otehrwise the commited styles get reverted
8830        if (this.transformAnimation) this.transformAnimation.cancel();
8831        newState.forEachRootNode(node => {
8832          restoreNodeVisualState(node);
8833          restoreNodeInlineStyles(node);
8834        });
8835        for (let i = 0, l = transformed.length; i < l; i++) {
8836          const $el = transformed[i];
8837          $el.style.transform = newState.getComputedValue($el, 'transform');
8838        }
8839        if (this.root.classList.contains('is-animated')) {
8840          this.root.classList.remove('is-animated');
8841          if (onComplete) onComplete(this.timeline);
8842        }
8843        // Avoid CSS transitions at the end of the animation by restoring them on the next frame
8844        requestAnimationFrame(() => {
8845          if (this.root.classList.contains('is-animated')) return;
8846          restoreLayoutTransition(this.transitionMuteStore);
8847        });
8848      };
8849      tlParams.onPause = () => {
8850        if (!this.root.classList.contains('is-animated')) return;
8851        if (this.transformAnimation) this.transformAnimation.cancel();
8852        newState.forEachRootNode(restoreNodeVisualState);
8853        this.root.classList.remove('is-animated');
8854        if (onComplete) onComplete(this.timeline);
8855        if (onPause) onPause(this.timeline);
8856      };
8857      tlParams.composition = false;
8858
8859      const swapAtParams = mergeObjects(mergeObjects(params.swapAt || {}, this.swapAtParams), animationTimings);
8860      const enterFromParams = mergeObjects(mergeObjects(params.enterFrom || {}, this.enterFromParams), animationTimings);
8861      const leaveToParams = mergeObjects(mergeObjects(params.leaveTo || {}, this.leaveToParams), animationTimings);
8862      const [ swapAtProps, swapAtTimings ] = splitPropertiesFromParams(swapAtParams);
8863      const [ enterFromProps, enterFromTimings ] = splitPropertiesFromParams(enterFromParams);
8864      const [ leaveToProps, leaveToTimings ] = splitPropertiesFromParams(leaveToParams);
8865
8866      const oldState = this.oldState;
8867      const newState = this.newState;
8868      const animating = this.animating;
8869      const swapping = this.swapping;
8870      const entering = this.entering;
8871      const leaving = this.leaving;
8872      const pendingRemoval = this.pendingRemoval;
8873
8874      animating.length = swapping.length = entering.length = leaving.length = 0;
8875
8876      // Mute old state CSS transitions to prevent wrong properties calculation
8877      oldState.forEachRootNode(muteNodeTransition);
8878      // Capture the new state before animation
8879      newState.record();
8880      newState.forEachRootNode(recordNodeInlineStyles);
8881
8882      const targets = [];
8883      const animated = [];
8884      const transformed = [];
8885      const animatedSwap = [];
8886      const rootNode = newState.rootNode;
8887      const $root = rootNode.$el;
8888
8889      newState.forEachRootNode(node => {
8890
8891        const $el = node.$el;
8892        const id = node.id;
8893        const parent = node.parentNode;
8894        const parentAdded = parent ? parent.branchAdded : false;
8895        const parentRemoved = parent ? parent.branchRemoved : false;
8896        const parentNotRendered = parent ? parent.branchNotRendered : false;
8897
8898        let oldStateNode = oldState.nodes.get(id);
8899
8900        const hasNoOldState = !oldStateNode;
8901
8902        if (hasNoOldState) {
8903          oldStateNode = cloneNodeProperties(node, /** @type {LayoutNode} */({}), oldState);
8904          oldState.nodes.set(id, oldStateNode);
8905          oldStateNode.measuredIsRemoved = true;
8906        } else if (oldStateNode.measuredIsRemoved && !node.measuredIsRemoved) {
8907          cloneNodeProperties(node, oldStateNode, oldState);
8908          oldStateNode.measuredIsRemoved = true;
8909        }
8910
8911        const oldParentNode = oldStateNode.parentNode;
8912        const oldParentId = oldParentNode ? oldParentNode.id : null;
8913        const newParentId = parent ? parent.id : null;
8914        const parentChanged = oldParentId !== newParentId;
8915        const elementChanged = oldStateNode.$el !== node.$el;
8916        const wasRemovedBefore = oldStateNode.measuredIsRemoved;
8917        const isRemovedNow = node.measuredIsRemoved;
8918
8919        // Recalculate postion relative to their parent for elements that have been moved
8920        if (!oldStateNode.measuredIsRemoved && !isRemovedNow && !hasNoOldState && (parentChanged || elementChanged)) {
8921          const oldAbsoluteLeft = oldStateNode.properties.left;
8922          const oldAbsoluteTop = oldStateNode.properties.top;
8923          const newParent = parent || newState.rootNode;
8924          const oldParent = newParent.id ? oldState.nodes.get(newParent.id) : null;
8925          const parentLeft = oldParent ? oldParent.properties.left : newParent.properties.left;
8926          const parentTop = oldParent ? oldParent.properties.top : newParent.properties.top;
8927          const borderLeft = oldParent ? oldParent.properties.clientLeft : newParent.properties.clientLeft;
8928          const borderTop = oldParent ? oldParent.properties.clientTop : newParent.properties.clientTop;
8929          oldStateNode.properties.x = oldAbsoluteLeft - parentLeft - borderLeft;
8930          oldStateNode.properties.y = oldAbsoluteTop - parentTop - borderTop;
8931        }
8932
8933        if (node.hasVisibilitySwap) {
8934          if (node.hasVisibilityHidden) {
8935            node.$el.style.visibility = 'visible';
8936            node.$measure.style.visibility = 'hidden';
8937          }
8938          if (node.hasDisplayNone) {
8939            node.$el.style.display = oldStateNode.measuredDisplay || node.measuredDisplay || '';
8940            // Setting visibility 'hidden' instead of display none to avoid calculation issues
8941            node.$measure.style.visibility = 'hidden';
8942            // @TODO: check why setting display here can cause calculation issues
8943            // node.$measure.style.display = 'none';
8944          }
8945        }
8946
8947        const wasPendingRemoval = pendingRemoval.has($el);
8948        const wasVisibleBefore = oldStateNode.measuredIsVisible;
8949        const isVisibleNow = node.measuredIsVisible;
8950        const becomeVisible = !wasVisibleBefore && isVisibleNow && !parentNotRendered;
8951        const topLevelAdded = !isRemovedNow && (wasRemovedBefore || wasPendingRemoval) && !parentAdded;
8952        const newlyRemoved = isRemovedNow && !wasRemovedBefore && !parentRemoved;
8953        const topLevelRemoved = newlyRemoved || isRemovedNow && wasPendingRemoval && !parentRemoved;
8954
8955        node.branchAdded = parentAdded || topLevelAdded;
8956        node.branchRemoved = parentRemoved || topLevelRemoved;
8957        node.branchNotRendered = parentNotRendered || isRemovedNow;
8958
8959        if (isRemovedNow && wasVisibleBefore) {
8960          node.$el.style.display = oldStateNode.measuredDisplay;
8961          node.$el.style.visibility = 'visible';
8962          cloneNodeProperties(oldStateNode, node, newState);
8963        }
8964
8965        // Node is leaving
8966        if (newlyRemoved) {
8967          if (node.isTarget) {
8968            leaving.push($el);
8969            node.isLeaving = true;
8970          }
8971          pendingRemoval.add($el);
8972        } else if (!isRemovedNow && wasPendingRemoval) {
8973          pendingRemoval.delete($el);
8974        }
8975
8976        // Node is entering
8977        if ((topLevelAdded && !parentNotRendered) || becomeVisible) {
8978          updateNodeProperties(oldStateNode, enterFromProps);
8979          if (node.isTarget) {
8980            entering.push($el);
8981            node.isEntering = true;
8982          }
8983        // Node is leaving
8984        } else if (topLevelRemoved && !parentNotRendered) {
8985          updateNodeProperties(node, leaveToProps);
8986        }
8987
8988        // Node is animating
8989        // The animating array is used only to calculate delays and duration on root children
8990        if (node !== rootNode && node.isTarget && !node.isEntering && !node.isLeaving) {
8991          animating.push($el);
8992        }
8993
8994        targets.push($el);
8995
8996      });
8997
8998      let enteringIndex = 0;
8999      let leavingIndex = 0;
9000      let animatingIndex = 0;
9001
9002      newState.forEachRootNode(node => {
9003
9004        const $el = node.$el;
9005        const parent = node.parentNode;
9006        const oldStateNode = oldState.nodes.get(node.id);
9007        const nodeProperties = node.properties;
9008        const oldStateNodeProperties = oldStateNode.properties;
9009
9010        // Use closest animated parent index and total values so that children staggered delays are in sync with their parent
9011        let animatedParent = parent !== rootNode && parent;
9012        while (animatedParent && !animatedParent.isTarget && animatedParent !== rootNode) {
9013          animatedParent = animatedParent.parentNode;
9014        }
9015
9016        const animatingTotal = animating.length;
9017
9018        // Root is always animated first in sync with the first child (animating.length is the total of children)
9019        if (node === rootNode) {
9020          node.index = 0;
9021          node.total = animatingTotal;
9022          updateNodeTimingParams(node, animationTimings);
9023        } else if (node.isEntering) {
9024          node.index = animatedParent ? animatedParent.index : enteringIndex;
9025          node.total = animatedParent ? animatingTotal : entering.length;
9026          updateNodeTimingParams(node, enterFromTimings);
9027          enteringIndex++;
9028        } else if (node.isLeaving) {
9029          node.index = animatedParent ? animatedParent.index : leavingIndex;
9030          node.total = animatedParent ? animatingTotal : leaving.length;
9031          leavingIndex++;
9032          updateNodeTimingParams(node, leaveToTimings);
9033        } else if (node.isTarget) {
9034          node.index = animatingIndex++;
9035          node.total = animatingTotal;
9036          updateNodeTimingParams(node, animationTimings);
9037        } else {
9038          node.index = animatedParent ? animatedParent.index : 0;
9039          node.total = animatingTotal;
9040          updateNodeTimingParams(node, swapAtTimings);
9041        }
9042
9043        // Make sure the old state node has its inex and total values up to date for valid "from" function values calculation
9044        oldStateNode.index = node.index;
9045        oldStateNode.total = node.total;
9046
9047        // Computes all values up front so we can check for changes and we don't have to re-compute them inside the animation props
9048        for (let prop in nodeProperties) {
9049          nodeProperties[prop] = getFunctionValue(nodeProperties[prop], $el, node.index, node.total);
9050          oldStateNodeProperties[prop] = getFunctionValue(oldStateNodeProperties[prop], $el, oldStateNode.index, oldStateNode.total);
9051        }
9052
9053        // Use a 1px tolerance to detect dimensions changes to prevent width / height animations on barelly visible elements
9054        const sizeTolerance = 1;
9055        const widthChanged = Math.abs(nodeProperties.width - oldStateNodeProperties.width) > sizeTolerance;
9056        const heightChanged = Math.abs(nodeProperties.height - oldStateNodeProperties.height) > sizeTolerance;
9057
9058        node.sizeChanged = (widthChanged || heightChanged);
9059
9060        // const hiddenStateChanged = (topLevelAdded || newlyRemoved) && wasRemovedBefore !== isRemovedNow;
9061
9062        if (node.isTarget && (!node.measuredIsRemoved && oldStateNode.measuredIsVisible || node.measuredIsRemoved && node.measuredIsVisible)) {
9063          if (!node.isInlined && (nodeProperties.transform !== 'none' || oldStateNodeProperties.transform !== 'none')) {
9064            node.hasTransform = true;
9065            transformed.push($el);
9066          }
9067          for (let prop in nodeProperties) {
9068            // if (prop !== 'transform' && (nodeProperties[prop] !== oldStateNodeProperties[prop] || hiddenStateChanged)) {
9069            if (prop !== 'transform' && (nodeProperties[prop] !== oldStateNodeProperties[prop])) {
9070              animated.push($el);
9071              break;
9072            }
9073          }
9074        }
9075
9076        if (!node.isTarget) {
9077          swapping.push($el);
9078          if (node.sizeChanged && parent && parent.isTarget && parent.sizeChanged) {
9079            if (!node.isInlined && swapAtProps.transform) {
9080              node.hasTransform = true;
9081              transformed.push($el);
9082            }
9083            animatedSwap.push($el);
9084          }
9085        }
9086
9087      });
9088
9089      const timingParams = {
9090        delay: (/** @type {HTMLElement} */$el) => newState.getNode($el).delay,
9091        duration: (/** @type {HTMLElement} */$el) => newState.getNode($el).duration,
9092        ease: (/** @type {HTMLElement} */$el) => newState.getNode($el).ease,
9093      };
9094
9095      tlParams.defaults = timingParams;
9096
9097      this.timeline = createTimeline(tlParams);
9098
9099      // Imediatly return the timeline if no layout changes detected
9100      if (!animated.length && !transformed.length && !swapping.length) {
9101        // Make sure to restore all CSS transition if no animation
9102        restoreLayoutTransition(this.transitionMuteStore);
9103        return this.timeline.complete();
9104      }
9105
9106      if (targets.length) {
9107
9108        this.root.classList.add('is-animated');
9109
9110        for (let i = 0, l = targets.length; i < l; i++) {
9111          const $el = targets[i];
9112          const id = $el.dataset.layoutId;
9113          const oldNode = oldState.nodes.get(id);
9114          const newNode = newState.nodes.get(id);
9115          const oldNodeState = oldNode.properties;
9116
9117          // muteNodeTransition(newNode);
9118
9119          // Don't animate dimensions and positions of inlined elements
9120          if (!newNode.isInlined) {
9121            // Display grid can mess with the absolute positioning, so set it to block during transition
9122            if (oldNode.measuredDisplay === 'grid' || newNode.measuredDisplay === 'grid') $el.style.setProperty('display', 'block', 'important');
9123            // All children must be in position absolute or fixed
9124            if ($el !== $root || this.absoluteCoords) {
9125              $el.style.position = this.absoluteCoords ? 'fixed' : 'absolute';
9126              $el.style.left = '0px';
9127              $el.style.top = '0px';
9128              $el.style.marginLeft = '0px';
9129              $el.style.marginTop = '0px';
9130              $el.style.translate = `${oldNodeState.x}px ${oldNodeState.y}px`;
9131            }
9132            if ($el === $root && newNode.measuredPosition === 'static') {
9133              $el.style.position = 'relative';
9134              // Cancel left / trop in case the static element had muted values now activated by potision relative
9135              $el.style.left = '0px';
9136              $el.style.top = '0px';
9137            }
9138            $el.style.width = `${oldNodeState.width}px`;
9139            $el.style.height = `${oldNodeState.height}px`;
9140            // Overrides user defined min and max to prevents width and height clamping
9141            $el.style.minWidth = `auto`;
9142            $el.style.minHeight = `auto`;
9143            $el.style.maxWidth = `none`;
9144            $el.style.maxHeight = `none`;
9145          }
9146        }
9147
9148        // Restore the scroll position if the oldState differs from the current state
9149        if (oldState.scrollX !== window.scrollX || oldState.scrollY !== window.scrollY) {
9150          // Restoring in the next frame avoids race conditions if for example a waapi animation commit styles that affect the root height
9151          requestAnimationFrame(() => window.scrollTo(oldState.scrollX, oldState.scrollY));
9152        }
9153
9154        for (let i = 0, l = animated.length; i < l; i++) {
9155          const $el = animated[i];
9156          const id = $el.dataset.layoutId;
9157          const oldNode = oldState.nodes.get(id);
9158          const newNode = newState.nodes.get(id);
9159          const oldNodeState = oldNode.properties;
9160          const newNodeState = newNode.properties;
9161          let nodeHasChanged = false;
9162          /** @type {AnimationParams} */
9163          const animatedProps = {
9164            composition: 'none',
9165          };
9166          if (!newNode.isInlined) {
9167            if (oldNodeState.width !== newNodeState.width) {
9168              animatedProps.width = [oldNodeState.width, newNodeState.width];
9169              nodeHasChanged = true;
9170            }
9171            if (oldNodeState.height !== newNodeState.height) {
9172              animatedProps.height = [oldNodeState.height, newNodeState.height];
9173              nodeHasChanged = true;
9174            }
9175            // If the node has transforms we handle the translate animation in wappi otherwise translate and other transforms can be out of sync
9176            // Always animate translate
9177            if (!newNode.hasTransform) {
9178              animatedProps.translate = [`${oldNodeState.x}px ${oldNodeState.y}px`, `${newNodeState.x}px ${newNodeState.y}px`];
9179              nodeHasChanged = true;
9180            }
9181          }
9182          this.properties.forEach(prop => {
9183            const oldVal = oldNodeState[prop];
9184            const newVal = newNodeState[prop];
9185            if (prop !== 'transform' && oldVal !== newVal) {
9186              animatedProps[prop] = [oldVal, newVal];
9187              nodeHasChanged = true;
9188            }
9189          });
9190          if (nodeHasChanged) {
9191            this.timeline.add($el, animatedProps, 0);
9192          }
9193        }
9194
9195      }
9196
9197      if (swapping.length) {
9198
9199        for (let i = 0, l = swapping.length; i < l; i++) {
9200          const $el = swapping[i];
9201          const oldNode = oldState.getNode($el);
9202          if (!oldNode.isInlined) {
9203            const oldNodeProps = oldNode.properties;
9204            $el.style.width = `${oldNodeProps.width}px`;
9205            $el.style.height = `${oldNodeProps.height}px`;
9206            // Overrides user defined min and max to prevents width and height clamping
9207            $el.style.minWidth = `auto`;
9208            $el.style.minHeight = `auto`;
9209            $el.style.maxWidth = `none`;
9210            $el.style.maxHeight = `none`;
9211            $el.style.translate = `${oldNodeProps.x}px ${oldNodeProps.y}px`;
9212          }
9213          this.properties.forEach(prop => {
9214            if (prop !== 'transform') {
9215              $el.style[prop] = `${oldState.getComputedValue($el, prop)}`;
9216            }
9217          });
9218        }
9219
9220        for (let i = 0, l = swapping.length; i < l; i++) {
9221          const $el = swapping[i];
9222          const newNode = newState.getNode($el);
9223          const newNodeProps = newNode.properties;
9224          this.timeline.call(() => {
9225            if (!newNode.isInlined) {
9226              $el.style.width = `${newNodeProps.width}px`;
9227              $el.style.height = `${newNodeProps.height}px`;
9228              // Overrides user defined min and max to prevents width and height clamping
9229              $el.style.minWidth = `auto`;
9230              $el.style.minHeight = `auto`;
9231              $el.style.maxWidth = `none`;
9232              $el.style.maxHeight = `none`;
9233              $el.style.translate = `${newNodeProps.x}px ${newNodeProps.y}px`;
9234            }
9235            this.properties.forEach(prop => {
9236              if (prop !== 'transform') {
9237                $el.style[prop] = `${newState.getComputedValue($el, prop)}`;
9238              }
9239            });
9240          }, newNode.delay + newNode.duration / 2);
9241        }
9242
9243        if (animatedSwap.length) {
9244          const ease = parseEase(newState.nodes.get(animatedSwap[0].dataset.layoutId).ease);
9245          const inverseEased = t => 1 - ease(1 - t);
9246          const animatedSwapParams = /** @type {AnimationParams} */({});
9247          if (swapAtProps) {
9248            for (let prop in swapAtProps) {
9249              if (prop !== 'transform') {
9250                animatedSwapParams[prop] = [
9251                  { from: (/** @type {HTMLElement} */$el) => oldState.getComputedValue($el, prop), to: swapAtProps[prop] },
9252                  { from: swapAtProps[prop], to: (/** @type {HTMLElement} */$el) => newState.getComputedValue($el, prop), ease: inverseEased }
9253                ];
9254              }
9255            }
9256          }
9257          this.timeline.add(animatedSwap, animatedSwapParams, 0);
9258        }
9259
9260      }
9261
9262      const transformedLength = transformed.length;
9263
9264      if (transformedLength) {
9265        // We only need to set the transform property here since translate is alread defined in the targets loop
9266        for (let i = 0; i < transformedLength; i++) {
9267          const $el = transformed[i];
9268          $el.style.translate = `${oldState.getComputedValue($el, 'x')}px ${oldState.getComputedValue($el, 'y')}px`,
9269          $el.style.transform = oldState.getComputedValue($el, 'transform');
9270          if (animatedSwap.includes($el)) {
9271            const node = newState.getNode($el);
9272            node.ease = getFunctionValue(swapAtParams.ease, $el, node.index, node.total);
9273            node.duration = getFunctionValue(swapAtParams.duration, $el, node.index, node.total);
9274          }
9275        }
9276        this.transformAnimation = waapi.animate(transformed, {
9277          translate: (/** @type {HTMLElement} */$el) => `${newState.getComputedValue($el, 'x')}px ${newState.getComputedValue($el, 'y')}px`,
9278          transform: (/** @type {HTMLElement} */$el) => {
9279            const newValue = newState.getComputedValue($el, 'transform');
9280            if (!animatedSwap.includes($el)) return newValue;
9281            const oldValue = oldState.getComputedValue($el, 'transform');
9282            const node = newState.getNode($el);
9283            return [oldValue, getFunctionValue(swapAtProps.transform, $el, node.index, node.total), newValue]
9284          },
9285          autoplay: false,
9286          persist: true,
9287          ...timingParams,
9288        });
9289        this.timeline.sync(this.transformAnimation, 0);
9290      }
9291
9292      return this.timeline.init();
9293    }
9294
9295    /**
9296     * @param {(layout: this) => void} callback
9297     * @param {LayoutAnimationParams} [params]
9298     * @return {Timeline}
9299     */
9300    update(callback, params = {}) {
9301      this.record();
9302      callback(this);
9303      return this.animate(params);
9304    }
9305  }
9306
9307  /**
9308   * @param {DOMTargetSelector} root
9309   * @param {AutoLayoutParams} [params]
9310   * @return {AutoLayout}
9311   */
9312  const createLayout = (root, params) => new AutoLayout(root, params);
9313
9314  // Chain-able utilities
9315
9316  const numberUtils = numberImports; // Needed to keep the import when bundling
9317
9318  const chainables = {};
9319
9320  /**
9321   * @callback UtilityFunction
9322   * @param {...*} args
9323   * @return {Number|String}
9324   *
9325   * @param {UtilityFunction} fn
9326   * @param {Number} [last=0]
9327   * @return {function(...(Number|String)): function(Number|String): (Number|String)}
9328   */
9329  const curry = (fn, last = 0) => (...args) => last ? v => fn(...args, v) : v => fn(v, ...args);
9330
9331  /**
9332   * @param {Function} fn
9333   * @return {function(...(Number|String))}
9334   */
9335  const chain = fn => {
9336     return (...args) => {
9337      const result = fn(...args);
9338      return new Proxy(noop, {
9339        apply: (_, __, [v]) => result(v),
9340        get: (_, prop) => chain(/**@param {...Number|String} nextArgs */(...nextArgs) => {
9341          const nextResult = chainables[prop](...nextArgs);
9342          return (/**@type {Number|String} */v) => nextResult(result(v));
9343        })
9344      });
9345    }
9346  };
9347
9348  /**
9349   * @param {UtilityFunction} fn
9350   * @param {String} name
9351   * @param {Number} [right]
9352   * @return {function(...(Number|String)): UtilityFunction}
9353   */
9354  const makeChainable = (name, fn, right = 0) => {
9355    const chained = (...args) => (args.length < fn.length ? chain(curry(fn, right)) : fn)(...args);
9356    if (!chainables[name]) chainables[name] = chained;
9357    return chained;
9358  };
9359
9360  /**
9361   * @typedef {Object} ChainablesMap
9362   * @property {ChainedClamp} clamp
9363   * @property {ChainedRound} round
9364   * @property {ChainedSnap} snap
9365   * @property {ChainedWrap} wrap
9366   * @property {ChainedLerp} lerp
9367   * @property {ChainedDamp} damp
9368   * @property {ChainedMapRange} mapRange
9369   * @property {ChainedRoundPad} roundPad
9370   * @property {ChainedPadStart} padStart
9371   * @property {ChainedPadEnd} padEnd
9372   * @property {ChainedDegToRad} degToRad
9373   * @property {ChainedRadToDeg} radToDeg
9374   */
9375
9376  /**
9377   * @callback ChainedUtilsResult
9378   * @param {Number} value - The value to process through the chained operations
9379   * @return {Number} The processed result
9380   */
9381
9382  /**
9383   * @typedef {ChainablesMap & ChainedUtilsResult} ChainableUtil
9384   */
9385
9386  // Chainable
9387
9388  /**
9389   * @callback ChainedRoundPad
9390   * @param {Number} decimalLength - Number of decimal places
9391   * @return {ChainableUtil}
9392   */
9393  const roundPad = /** @type {typeof numberUtils.roundPad & ChainedRoundPad} */(makeChainable('roundPad', numberUtils.roundPad));
9394
9395  /**
9396   * @callback ChainedPadStart
9397   * @param {Number} totalLength - Target length
9398   * @param {String} padString - String to pad with
9399   * @return {ChainableUtil}
9400   */
9401  const padStart = /** @type {typeof numberUtils.padStart & ChainedPadStart} */(makeChainable('padStart', numberUtils.padStart));
9402
9403  /**
9404   * @callback ChainedPadEnd
9405   * @param {Number} totalLength - Target length
9406   * @param {String} padString - String to pad with
9407   * @return {ChainableUtil}
9408   */
9409  const padEnd = /** @type {typeof numberUtils.padEnd & ChainedPadEnd} */(makeChainable('padEnd', numberUtils.padEnd));
9410
9411  /**
9412   * @callback ChainedWrap
9413   * @param {Number} min - Minimum boundary
9414   * @param {Number} max - Maximum boundary
9415   * @return {ChainableUtil}
9416   */
9417  const wrap = /** @type {typeof numberUtils.wrap & ChainedWrap} */(makeChainable('wrap', numberUtils.wrap));
9418
9419  /**
9420   * @callback ChainedMapRange
9421   * @param {Number} inLow - Input range minimum
9422   * @param {Number} inHigh - Input range maximum
9423   * @param {Number} outLow - Output range minimum
9424   * @param {Number} outHigh - Output range maximum
9425   * @return {ChainableUtil}
9426   */
9427  const mapRange = /** @type {typeof numberUtils.mapRange & ChainedMapRange} */(makeChainable('mapRange', numberUtils.mapRange));
9428
9429  /**
9430   * @callback ChainedDegToRad
9431   * @return {ChainableUtil}
9432   */
9433  const degToRad = /** @type {typeof numberUtils.degToRad & ChainedDegToRad} */(makeChainable('degToRad', numberUtils.degToRad));
9434
9435  /**
9436   * @callback ChainedRadToDeg
9437   * @return {ChainableUtil}
9438   */
9439  const radToDeg = /** @type {typeof numberUtils.radToDeg & ChainedRadToDeg} */(makeChainable('radToDeg', numberUtils.radToDeg));
9440
9441  /**
9442   * @callback ChainedSnap
9443   * @param {Number|Array<Number>} increment - Step size or array of snap points
9444   * @return {ChainableUtil}
9445   */
9446  const snap = /** @type {typeof numberUtils.snap & ChainedSnap} */(makeChainable('snap', numberUtils.snap));
9447
9448  /**
9449   * @callback ChainedClamp
9450   * @param {Number} min - Minimum boundary
9451   * @param {Number} max - Maximum boundary
9452   * @return {ChainableUtil}
9453   */
9454  const clamp = /** @type {typeof numberUtils.clamp & ChainedClamp} */(makeChainable('clamp', numberUtils.clamp));
9455
9456  /**
9457   * @callback ChainedRound
9458   * @param {Number} decimalLength - Number of decimal places
9459   * @return {ChainableUtil}
9460   */
9461  const round = /** @type {typeof numberUtils.round & ChainedRound} */(makeChainable('round', numberUtils.round));
9462
9463  /**
9464   * @callback ChainedLerp
9465   * @param {Number} start - Starting value
9466   * @param {Number} end - Ending value
9467   * @return {ChainableUtil}
9468   */
9469  const lerp = /** @type {typeof numberUtils.lerp & ChainedLerp} */(makeChainable('lerp', numberUtils.lerp, 1));
9470
9471  /**
9472   * @callback ChainedDamp
9473   * @param {Number} start - Starting value
9474   * @param {Number} end - Target value
9475   * @param {Number} deltaTime - Delta time in ms
9476   * @return {ChainableUtil}
9477   */
9478  const damp = /** @type {typeof numberUtils.damp & ChainedDamp} */(makeChainable('damp', numberUtils.damp, 1));
9479
9480  /**
9481   * Generate a random number between optional min and max (inclusive) and decimal precision
9482   *
9483   * @callback RandomNumberGenerator
9484   * @param    {Number} [min=0] - The minimum value (inclusive)
9485   * @param    {Number} [max=1] - The maximum value (inclusive)
9486   * @param    {Number} [decimalLength=0] - Number of decimal places to round to
9487   * @return   {Number} A random number between min and max
9488   */
9489
9490  /**
9491   * Generates a random number between min and max (inclusive) with optional decimal precision
9492   *
9493   * @type {RandomNumberGenerator}
9494   */
9495  const random = (min = 0, max = 1, decimalLength = 0) => {
9496    const m = 10 ** decimalLength;
9497    return Math.floor((Math.random() * (max - min + (1 / m)) + min) * m) / m;
9498  };
9499
9500  let _seed = 0;
9501
9502  /**
9503   * Creates a seeded pseudorandom number generator function
9504   *
9505   * @param  {Number} [seed] - The seed value for the random number generator
9506   * @param  {Number} [seededMin=0] - The minimum default value (inclusive) of the returned function
9507   * @param  {Number} [seededMax=1] - The maximum default value (inclusive) of the returned function
9508   * @param  {Number} [seededDecimalLength=0] - Default number of decimal places to round to of the returned function
9509   * @return {RandomNumberGenerator} A function to generate a random number between optional min and max (inclusive) and decimal precision
9510   */
9511  const createSeededRandom = (seed, seededMin = 0, seededMax = 1, seededDecimalLength = 0) => {
9512    let t = seed === undefined ? _seed++ : seed;
9513    return (min = seededMin, max = seededMax, decimalLength = seededDecimalLength) => {
9514      t += 0x6D2B79F5;
9515      t = Math.imul(t ^ t >>> 15, t | 1);
9516      t ^= t + Math.imul(t ^ t >>> 7, t | 61);
9517      const m = 10 ** decimalLength;
9518      return Math.floor(((((t ^ t >>> 14) >>> 0) / 4294967296) * (max - min + (1 / m)) + min) * m) / m;
9519    }
9520  };
9521
9522  /**
9523   * Picks a random element from an array or a string
9524   *
9525   * @template T
9526   * @param    {String|Array<T>} items - The array or string to pick from
9527   * @return   {String|T} A random element from the array or character from the string
9528   */
9529  const randomPick = items => items[random(0, items.length - 1)];
9530
9531  /**
9532   * Shuffles an array in-place using the Fisher-Yates algorithm
9533   * Adapted from https://bost.ocks.org/mike/shuffle/
9534   *
9535   * @param  {Array} items - The array to shuffle (will be modified in-place)
9536   * @return {Array} The same array reference, now shuffled
9537   */
9538  const shuffle = items => {
9539    let m = items.length, t, i;
9540    while (m) { i = random(0, --m); t = items[m]; items[m] = items[i]; items[i] = t; }
9541    return items;
9542  };
9543
9544  
9545
9546  
9547
9548  /**
9549   * @overload
9550   * @param {Number} val
9551   * @param {StaggerParams} [params]
9552   * @return {StaggerFunction<Number>}
9553   */
9554  /**
9555   * @overload
9556   * @param {String} val
9557   * @param {StaggerParams} [params]
9558   * @return {StaggerFunction<String>}
9559   */
9560  /**
9561   * @overload
9562   * @param {[Number, Number]} val
9563   * @param {StaggerParams} [params]
9564   * @return {StaggerFunction<Number>}
9565   */
9566  /**
9567   * @overload
9568   * @param {[String, String]} val
9569   * @param {StaggerParams} [params]
9570   * @return {StaggerFunction<String>}
9571   */
9572  /**
9573   * @param {Number|String|[Number, Number]|[String, String]} val The staggered value or range
9574   * @param {StaggerParams} [params] The stagger parameters
9575   * @return {StaggerFunction<Number|String>}
9576   */
9577  const stagger = (val, params = {}) => {
9578    let values = [];
9579    let maxValue = 0;
9580    const from = params.from;
9581    const reversed = params.reversed;
9582    const ease = params.ease;
9583    const hasEasing = !isUnd(ease);
9584    const hasSpring = hasEasing && !isUnd(/** @type {Spring} */(ease).ease);
9585    const staggerEase = hasSpring ? /** @type {Spring} */(ease).ease : hasEasing ? parseEase(ease) : null;
9586    const grid = params.grid;
9587    const axis = params.axis;
9588    const customTotal = params.total;
9589    const fromFirst = isUnd(from) || from === 0 || from === 'first';
9590    const fromCenter = from === 'center';
9591    const fromLast = from === 'last';
9592    const fromRandom = from === 'random';
9593    const isRange = isArr(val);
9594    const useProp = params.use;
9595    const val1 = isRange ? parseNumber(val[0]) : parseNumber(val);
9596    const val2 = isRange ? parseNumber(val[1]) : 0;
9597    const unitMatch = unitsExecRgx.exec((isRange ? val[1] : val) + emptyString);
9598    const start = params.start || 0 + (isRange ? val1 : 0);
9599    let fromIndex = fromFirst ? 0 : isNum(from) ? from : 0;
9600    return (target, i, t, tl) => {
9601      const [ registeredTarget ] = registerTargets(target);
9602      const total = isUnd(customTotal) ? t : customTotal;
9603      const customIndex = !isUnd(useProp) ? isFnc(useProp) ? useProp(registeredTarget, i, total) : getOriginalAnimatableValue(registeredTarget, useProp) : false;
9604      const staggerIndex = isNum(customIndex) || isStr(customIndex) && isNum(+customIndex) ? +customIndex : i;
9605      if (fromCenter) fromIndex = (total - 1) / 2;
9606      if (fromLast) fromIndex = total - 1;
9607      if (!values.length) {
9608        for (let index = 0; index < total; index++) {
9609          if (!grid) {
9610            values.push(abs(fromIndex - index));
9611          } else {
9612            const fromX = !fromCenter ? fromIndex % grid[0] : (grid[0] - 1) / 2;
9613            const fromY = !fromCenter ? floor(fromIndex / grid[0]) : (grid[1] - 1) / 2;
9614            const toX = index % grid[0];
9615            const toY = floor(index / grid[0]);
9616            const distanceX = fromX - toX;
9617            const distanceY = fromY - toY;
9618            let value = sqrt(distanceX * distanceX + distanceY * distanceY);
9619            if (axis === 'x') value = -distanceX;
9620            if (axis === 'y') value = -distanceY;
9621            values.push(value);
9622          }
9623          maxValue = max(...values);
9624        }
9625        if (staggerEase) values = values.map(val => staggerEase(val / maxValue) * maxValue);
9626        if (reversed) values = values.map(val => axis ? (val < 0) ? val * -1 : -val : abs(maxValue - val));
9627        if (fromRandom) values = shuffle(values);
9628      }
9629      const spacing = isRange ? (val2 - val1) / maxValue : val1;
9630      const offset = tl ? parseTimelinePosition(tl, isUnd(params.start) ? tl.iterationDuration : start) : /** @type {Number} */(start);
9631      /** @type {String|Number} */
9632      let output = offset + ((spacing * round$1(values[staggerIndex], 2)) || 0);
9633      if (params.modifier) output = params.modifier(output);
9634      if (unitMatch) output = `${output}${unitMatch[2]}`;
9635      return output;
9636    }
9637  };
9638
9639  var index$2 = /*#__PURE__*/Object.freeze({
9640    __proto__: null,
9641    $: registerTargets,
9642    clamp: clamp,
9643    cleanInlineStyles: cleanInlineStyles,
9644    createSeededRandom: createSeededRandom,
9645    damp: damp,
9646    degToRad: degToRad,
9647    get: get,
9648    keepTime: keepTime,
9649    lerp: lerp,
9650    mapRange: mapRange,
9651    padEnd: padEnd,
9652    padStart: padStart,
9653    radToDeg: radToDeg,
9654    random: random,
9655    randomPick: randomPick,
9656    remove: remove,
9657    round: round,
9658    roundPad: roundPad,
9659    set: set,
9660    shuffle: shuffle,
9661    snap: snap,
9662    stagger: stagger,
9663    sync: sync,
9664    wrap: wrap
9665  });
9666
9667  
9668
9669  /**
9670   * @param  {TargetsParam} path
9671   * @return {SVGGeometryElement|void}
9672   */
9673  const getPath = path => {
9674    const parsedTargets = parseTargets(path);
9675    const $parsedSvg = /** @type {SVGGeometryElement} */(parsedTargets[0]);
9676    if (!$parsedSvg || !isSvg($parsedSvg)) return console.warn(`${path} is not a valid SVGGeometryElement`);
9677    return $parsedSvg;
9678  };
9679
9680  
9681
9682  // Motion path animation
9683
9684  /**
9685   * @param {SVGGeometryElement} $path
9686   * @param {Number} totalLength
9687   * @param {Number} progress
9688   * @param {Number} lookup
9689   * @param {Boolean} shouldClamp
9690   * @return {DOMPoint}
9691   */
9692  const getPathPoint = ($path, totalLength, progress, lookup, shouldClamp) => {
9693    const point = progress + lookup;
9694    const pointOnPath = shouldClamp
9695      ? Math.max(0, Math.min(point, totalLength)) // Clamp between 0 and totalLength
9696      : (point % totalLength + totalLength) % totalLength; // Wrap around
9697    return $path.getPointAtLength(pointOnPath);
9698  };
9699
9700  /**
9701   * @param {SVGGeometryElement} $path
9702   * @param {String} pathProperty
9703   * @param {Number} [offset=0]
9704   * @return {FunctionValue}
9705   */
9706  const getPathProgess = ($path, pathProperty, offset = 0) => {
9707    return $el => {
9708      const totalLength = +($path.getTotalLength());
9709      const inSvg = $el[isSvgSymbol];
9710      const ctm = $path.getCTM();
9711      const shouldClamp = offset === 0;
9712      /** @type {TweenObjectValue} */
9713      return {
9714        from: 0,
9715        to: totalLength,
9716        /** @type {TweenModifier} */
9717        modifier: progress => {
9718          const offsetLength = offset * totalLength;
9719          const newProgress = progress + offsetLength;
9720          if (pathProperty === 'a') {
9721            const p0 = getPathPoint($path, totalLength, newProgress, -1, shouldClamp);
9722            const p1 = getPathPoint($path, totalLength, newProgress, 1, shouldClamp);
9723            return atan2(p1.y - p0.y, p1.x - p0.x) * 180 / PI;
9724          } else {
9725            const p = getPathPoint($path, totalLength, newProgress, 0, shouldClamp);
9726            return pathProperty === 'x' ?
9727              inSvg || !ctm ? p.x : p.x * ctm.a + p.y * ctm.c + ctm.e :
9728              inSvg || !ctm ? p.y : p.x * ctm.b + p.y * ctm.d + ctm.f
9729          }
9730        }
9731      }
9732    }
9733  };
9734
9735  /**
9736   * @param {TargetsParam} path
9737   * @param {Number} [offset=0]
9738   */
9739  const createMotionPath = (path, offset = 0) => {
9740    const $path = getPath(path);
9741    if (!$path) return;
9742    return {
9743      translateX: getPathProgess($path, 'x', offset),
9744      translateY: getPathProgess($path, 'y', offset),
9745      rotate: getPathProgess($path, 'a', offset),
9746    }
9747  };
9748
9749  
9750
9751  /**
9752   * @param {SVGGeometryElement} [$el]
9753   * @return {Number}
9754   */
9755  const getScaleFactor = $el => {
9756    let scaleFactor = 1;
9757    if ($el && $el.getCTM) {
9758      const ctm = $el.getCTM();
9759      if (ctm) {
9760        const scaleX = sqrt(ctm.a * ctm.a + ctm.b * ctm.b);
9761        const scaleY = sqrt(ctm.c * ctm.c + ctm.d * ctm.d);
9762        scaleFactor = (scaleX + scaleY) / 2;
9763      }
9764    }
9765    return scaleFactor;
9766  };
9767
9768  /**
9769   * Creates a proxy that wraps an SVGGeometryElement and adds drawing functionality.
9770   * @param {SVGGeometryElement} $el - The SVG element to transform into a drawable
9771   * @param {number} start - Starting position (0-1)
9772   * @param {number} end - Ending position (0-1)
9773   * @return {DrawableSVGGeometry} - Returns a proxy that preserves the original element's type with additional 'draw' attribute functionality
9774   */
9775  const createDrawableProxy = ($el, start, end) => {
9776    const pathLength = K;
9777    const computedStyles = getComputedStyle($el);
9778    const strokeLineCap = computedStyles.strokeLinecap;
9779    // @ts-ignore
9780    const $scalled = computedStyles.vectorEffect === 'non-scaling-stroke' ? $el : null;
vendor: 15,024 bytes, lines 9781-10156
9781    let currentCap = strokeLineCap;
9782
9783    const proxy = new Proxy($el, {
9784      get(target, property) {
9785        const value = target[property];
9786        if (property === proxyTargetSymbol) return target;
9787        if (property === 'setAttribute') {
9788          return (...args) => {
9789            if (args[0] === 'draw') {
9790              const value = args[1];
9791              const values = value.split(' ');
9792              const v1 = +values[0];
9793              const v2 = +values[1];
9794              // TOTO: Benchmark if performing two slices is more performant than one split
9795              // const spaceIndex = value.indexOf(' ');
9796              // const v1 = round(+value.slice(0, spaceIndex), precision);
9797              // const v2 = round(+value.slice(spaceIndex + 1), precision);
9798              const scaleFactor = getScaleFactor($scalled);
9799              const os = v1 * -pathLength * scaleFactor;
9800              const d1 = (v2 * pathLength * scaleFactor) + os;
9801              const d2 = (pathLength * scaleFactor +
9802                        ((v1 === 0 && v2 === 1) || (v1 === 1 && v2 === 0) ? 0 : 10 * scaleFactor) - d1);
9803              if (strokeLineCap !== 'butt') {
9804                const newCap = v1 === v2 ? 'butt' : strokeLineCap;
9805                if (currentCap !== newCap) {
9806                  target.style.strokeLinecap = `${newCap}`;
9807                  currentCap = newCap;
9808                }
9809              }
9810              target.setAttribute('stroke-dashoffset', `${os}`);
9811              target.setAttribute('stroke-dasharray', `${d1} ${d2}`);
9812            }
9813            return Reflect.apply(value, target, args);
9814          };
9815        }
9816
9817        if (isFnc(value)) {
9818          return (...args) => Reflect.apply(value, target, args);
9819        } else {
9820          return value;
9821        }
9822      }
9823    });
9824
9825    if ($el.getAttribute('pathLength') !== `${pathLength}`) {
9826      $el.setAttribute('pathLength', `${pathLength}`);
9827      proxy.setAttribute('draw', `${start} ${end}`);
9828    }
9829
9830    return /** @type {DrawableSVGGeometry} */(proxy);
9831  };
9832
9833  /**
9834   * Creates drawable proxies for multiple SVG elements.
9835   * @param {TargetsParam} selector - CSS selector, SVG element, or array of elements and selectors
9836   * @param {number} [start=0] - Starting position (0-1)
9837   * @param {number} [end=0] - Ending position (0-1)
9838   * @return {Array<DrawableSVGGeometry>} - Array of proxied elements with drawing functionality
9839   */
9840  const createDrawable = (selector, start = 0, end = 0) => {
9841    const els = parseTargets(selector);
9842    return els.map($el => createDrawableProxy(
9843      /** @type {SVGGeometryElement} */($el),
9844      start,
9845      end
9846    ));
9847  };
9848
9849  
9850
9851  /**
9852   * @param  {TargetsParam} path2
9853   * @param  {Number} [precision]
9854   * @return {FunctionValue}
9855   */
9856  const morphTo = (path2, precision = .33) => ($path1) => {
9857    const tagName1 = ($path1.tagName || '').toLowerCase();
9858    if (!tagName1.match(/^(path|polygon|polyline)$/)) {
9859      throw new Error(`Can't morph a <${$path1.tagName}> SVG element. Use <path>, <polygon> or <polyline>.`);
9860    }
9861    const $path2 = /** @type {SVGGeometryElement} */(getPath(path2));
9862    if (!$path2) {
9863      throw new Error("Can't morph to an invalid target. 'path2' must resolve to an existing <path>, <polygon> or <polyline> SVG element.");
9864    }
9865    const tagName2 = ($path2.tagName || '').toLowerCase();
9866    if (!tagName2.match(/^(path|polygon|polyline)$/)) {
9867      throw new Error(`Can't morph a <${$path2.tagName}> SVG element. Use <path>, <polygon> or <polyline>.`);
9868    }
9869    const isPath = $path1.tagName === 'path';
9870    const separator = isPath ? ' ' : ',';
9871    const previousPoints = $path1[morphPointsSymbol];
9872    if (previousPoints) $path1.setAttribute(isPath ? 'd' : 'points', previousPoints);
9873
9874    let v1 = '', v2 = '';
9875
9876    if (!precision) {
9877      v1 = $path1.getAttribute(isPath ? 'd' : 'points');
9878      v2 = $path2.getAttribute(isPath ? 'd' : 'points');
9879    } else {
9880      const length1 = /** @type {SVGGeometryElement} */($path1).getTotalLength();
9881      const length2 = $path2.getTotalLength();
9882      const maxPoints = Math.max(Math.ceil(length1 * precision), Math.ceil(length2 * precision));
9883      for (let i = 0; i < maxPoints; i++) {
9884        const t = i / (maxPoints - 1);
9885        const pointOnPath1 = /** @type {SVGGeometryElement} */($path1).getPointAtLength(length1 * t);
9886        const pointOnPath2 = $path2.getPointAtLength(length2 * t);
9887        const prefix = isPath ? (i === 0 ? 'M' : 'L') : '';
9888        v1 += prefix + round$1(pointOnPath1.x, 3) + separator + pointOnPath1.y + ' ';
9889        v2 += prefix + round$1(pointOnPath2.x, 3) + separator + pointOnPath2.y + ' ';
9890      }
9891    }
9892
9893    $path1[morphPointsSymbol] = v2;
9894
9895    return [v1, v2];
9896  };
9897
9898  var index$1 = /*#__PURE__*/Object.freeze({
9899    __proto__: null,
9900    createDrawable: createDrawable,
9901    createMotionPath: createMotionPath,
9902    morphTo: morphTo
9903  });
9904
9905  
9906
9907  const segmenter = (typeof Intl !== 'undefined') && Intl.Segmenter;
9908  const valueRgx = /\{value\}/g;
9909  const indexRgx = /\{i\}/g;
9910  const whiteSpaceGroupRgx = /(\s+)/;
9911  const whiteSpaceRgx = /^\s+$/;
9912  const lineType = 'line';
9913  const wordType = 'word';
9914  const charType = 'char';
9915  const dataLine = `data-line`;
9916
9917  /**
9918   * @typedef {Object} Segment
9919   * @property {String} segment
9920   * @property {Boolean} [isWordLike]
9921   */
9922
9923  /**
9924   * @typedef {Object} Segmenter
9925   * @property {function(String): Iterable<Segment>} segment
9926   */
9927
9928  /** @type {Segmenter} */
9929  let wordSegmenter = null;
9930  /** @type {Segmenter} */
9931  let graphemeSegmenter = null;
9932  let $splitTemplate = null;
9933
9934  /**
9935   * @param  {Segment} seg
9936   * @return {Boolean}
9937   */
9938  const isSegmentWordLike = seg => {
9939    return seg.isWordLike ||
9940           seg.segment === ' ' || // Consider spaces as words first, then handle them diffrently later
9941           isNum(+seg.segment);   // Safari doesn't considers numbers as words
9942  };
9943
9944  /**
9945   * @param {HTMLElement} $el
9946   */
9947  const setAriaHidden = $el => $el.setAttribute('aria-hidden', 'true');
9948
9949  /**
9950   * @param {DOMTarget} $el
9951   * @param {String} type
9952   * @return {Array<HTMLElement>}
9953   */
9954  const getAllTopLevelElements = ($el, type) => [.../** @type {*} */($el.querySelectorAll(`[data-${type}]:not([data-${type}] [data-${type}])`))];
9955
9956  const debugColors = { line: '#00D672', word: '#FF4B4B', char: '#5A87FF' };
9957
9958  /**
9959   * @param {HTMLElement} $el
9960   */
9961  const filterEmptyElements = $el => {
9962    if (!$el.childElementCount && !$el.textContent.trim()) {
9963      const $parent = $el.parentElement;
9964      $el.remove();
9965      if ($parent) filterEmptyElements($parent);
9966    }
9967  };
9968
9969  /**
9970   * @param {HTMLElement} $el
9971   * @param {Number} lineIndex
9972   * @param {Set<HTMLElement|Node>} bin
9973   * @returns {Set<HTMLElement|Node>}
9974   */
9975  const filterLineElements = ($el, lineIndex, bin) => {
9976    const dataLineAttr = $el.getAttribute(dataLine);
9977    if (dataLineAttr !== null && +dataLineAttr !== lineIndex || $el.tagName === 'BR') {
9978      bin.add($el);
9979      // Also remove adjacent whitespace-only text nodes
9980      const prev = $el.previousSibling;
9981      const next = $el.nextSibling;
9982      if (prev && prev.nodeType === 3 && whiteSpaceRgx.test(prev.textContent)) {
9983        bin.add(prev);
9984      }
9985      if (next && next.nodeType === 3 && whiteSpaceRgx.test(next.textContent)) {
9986        bin.add(next);
9987      }
9988    }
9989    let i = $el.childElementCount;
9990    while (i--) filterLineElements(/** @type {HTMLElement} */($el.children[i]), lineIndex, bin);
9991    return bin;
9992  };
9993
9994  /**
9995   * @param  {'line'|'word'|'char'} type
9996   * @param  {SplitTemplateParams} params
9997   * @return {String}
9998   */
9999  const generateTemplate = (type, params = {}) => {
10000    let template = ``;
10001    const classString = isStr(params.class) ? ` class="${params.class}"` : '';
10002    const cloneType = setValue(params.clone, false);
10003    const wrapType = setValue(params.wrap, false);
10004    const overflow = wrapType ? wrapType === true ? 'clip' : wrapType : cloneType ? 'clip' : false;
10005    if (wrapType) template += `<span${overflow ? ` style="overflow:${overflow};"` : ''}>`;
10006    template += `<span${classString}${cloneType ? ` style="position:relative;"` : ''} data-${type}="{i}">`;
10007    if (cloneType) {
10008      const left = cloneType === 'left' ? '-100%' : cloneType === 'right' ? '100%' : '0';
10009      const top = cloneType === 'top' ? '-100%' : cloneType === 'bottom' ? '100%' : '0';
10010      template += `<span>{value}</span>`;
10011      template += `<span inert style="position:absolute;top:${top};left:${left};white-space:nowrap;">{value}</span>`;
10012    } else {
10013      template += `{value}`;
10014    }
10015    template += `</span>`;
10016    if (wrapType) template += `</span>`;
10017    return template;
10018  };
10019
10020  /**
10021   * @param  {String|SplitFunctionValue} htmlTemplate
10022   * @param  {Array<HTMLElement>} store
10023   * @param  {Node|HTMLElement} node
10024   * @param  {DocumentFragment} $parentFragment
10025   * @param  {'line'|'word'|'char'} type
10026   * @param  {Boolean} debug
10027   * @param  {Number} lineIndex
10028   * @param  {Number} [wordIndex]
10029   * @param  {Number} [charIndex]
10030   * @return {HTMLElement}
10031   */
10032  const processHTMLTemplate = (htmlTemplate, store, node, $parentFragment, type, debug, lineIndex, wordIndex, charIndex) => {
10033    const isLine = type === lineType;
10034    const isChar = type === charType;
10035    const className = `_${type}_`;
10036    const template = isFnc(htmlTemplate) ? htmlTemplate(node) : htmlTemplate;
10037    const displayStyle = isLine ? 'block' : 'inline-block';
10038    $splitTemplate.innerHTML = template
10039      .replace(valueRgx, `<i class="${className}"></i>`)
10040      .replace(indexRgx, `${isChar ? charIndex : isLine ? lineIndex : wordIndex}`);
10041    const $content = $splitTemplate.content;
10042    const $highestParent = /** @type {HTMLElement} */($content.firstElementChild);
10043    const $split = /** @type {HTMLElement} */($content.querySelector(`[data-${type}]`)) || $highestParent;
10044    const $replacables = /** @type {NodeListOf<HTMLElement>} */($content.querySelectorAll(`i.${className}`));
10045    const replacablesLength = $replacables.length;
10046    if (replacablesLength) {
10047      $highestParent.style.display = displayStyle;
10048      $split.style.display = displayStyle;
10049      $split.setAttribute(dataLine, `${lineIndex}`);
10050      if (!isLine) {
10051        $split.setAttribute('data-word', `${wordIndex}`);
10052        if (isChar) $split.setAttribute('data-char', `${charIndex}`);
10053      }
10054      let i = replacablesLength;
10055      while (i--) {
10056        const $replace = $replacables[i];
10057        const $closestParent = $replace.parentElement;
10058        $closestParent.style.display = displayStyle;
10059        if (isLine) {
10060          $closestParent.innerHTML = /** @type {HTMLElement} */(node).innerHTML;
10061        } else {
10062          $closestParent.replaceChild(node.cloneNode(true), $replace);
10063        }
10064      }
10065      store.push($split);
10066      $parentFragment.appendChild($content);
10067    } else {
10068      console.warn(`The expression "{value}" is missing from the provided template.`);
10069    }
10070    if (debug) $highestParent.style.outline = `1px dotted ${debugColors[type]}`;
10071    return $highestParent;
10072  };
10073
10074  /**
10075   * A class that splits text into words and wraps them in span elements while preserving the original HTML structure.
10076   * @class
10077   */
10078  class TextSplitter {
10079    /**
10080     * @param  {HTMLElement|NodeList|String|Array<HTMLElement>} target
10081     * @param  {TextSplitterParams} [parameters]
10082     */
10083    constructor(target, parameters = {}) {
10084      // Only init segmenters when needed
10085      if (!wordSegmenter) wordSegmenter = segmenter ? new segmenter([], { granularity: wordType }) : {
10086        segment: (text) => {
10087          const segments = [];
10088          const words = text.split(whiteSpaceGroupRgx);
10089          for (let i = 0, l = words.length; i < l; i++) {
10090            const segment = words[i];
10091            segments.push({
10092              segment,
10093              isWordLike: !whiteSpaceRgx.test(segment), // Consider non-whitespace as word-like
10094            });
10095          }
10096          return segments;
10097        }
10098      };
10099      if (!graphemeSegmenter) graphemeSegmenter = segmenter ? new segmenter([], { granularity: 'grapheme' }) : {
10100        segment: text => [...text].map(char => ({ segment: char }))
10101      };
10102      if (!$splitTemplate && isBrowser) $splitTemplate = doc.createElement('template');
10103      if (scope.current) scope.current.register(this);
10104      const { words, chars, lines, accessible, includeSpaces, debug } = parameters;
10105      const $target = /** @type {HTMLElement} */((target = isArr(target) ? target[0] : target) && /** @type {Node} */(target).nodeType ? target : (getNodeList(target) || [])[0]);
10106      const lineParams = lines === true ? {} : lines;
10107      const wordParams = words === true || isUnd(words) ? {} : words;
10108      const charParams = chars === true ? {} : chars;
10109      this.debug = setValue(debug, false);
10110      this.includeSpaces = setValue(includeSpaces, false);
10111      this.accessible = setValue(accessible, true);
10112      this.linesOnly = lineParams && (!wordParams && !charParams);
10113      /** @type {String|false|SplitFunctionValue} */
10114      this.lineTemplate = isObj(lineParams) ? generateTemplate(lineType, /** @type {SplitTemplateParams} */(lineParams)) : lineParams;
10115      /** @type {String|false|SplitFunctionValue} */
10116      this.wordTemplate = isObj(wordParams) || this.linesOnly ? generateTemplate(wordType, /** @type {SplitTemplateParams} */(wordParams)) : wordParams;
10117      /** @type {String|false|SplitFunctionValue} */
10118      this.charTemplate = isObj(charParams) ? generateTemplate(charType, /** @type {SplitTemplateParams} */(charParams)) : charParams;
10119      this.$target = $target;
10120      this.html = $target && $target.innerHTML;
10121      this.lines = [];
10122      this.words = [];
10123      this.chars = [];
10124      this.effects = [];
10125      this.effectsCleanups = [];
10126      this.cache = null;
10127      this.ready = false;
10128      this.width = 0;
10129      this.resizeTimeout = null;
10130      const handleSplit = () => this.html && (lineParams || wordParams || charParams) && this.split();
10131      // Make sure this is declared before calling handleSplit() in case revert() is called inside an effect callback
10132      this.resizeObserver = new ResizeObserver(() => {
10133        // Use a setTimeout instead of a Timer for better tree shaking
10134        clearTimeout(this.resizeTimeout);
10135        this.resizeTimeout = setTimeout(() => {
10136          const currentWidth = /** @type {HTMLElement} */($target).offsetWidth;
10137          if (currentWidth === this.width) return;
10138          this.width = currentWidth;
10139          handleSplit();
10140        }, 150);
10141      });
10142      // Only declare the font ready promise when splitting by lines and not alreay split
10143      if (this.lineTemplate && !this.ready) {
10144        doc.fonts.ready.then(handleSplit);
10145      } else {
10146        handleSplit();
10147      }
10148      $target ? this.resizeObserver.observe($target) : console.warn('No Text Splitter target found.');
10149    }
10150
10151    /**
10152     * @param  {(...args: any[]) => Tickable | (() => void)} effect
10153     * @return this
10154     */
10155    addEffect(effect) {
10156      if (!isFnc(effect)) return console.warn('Effect must return a function.');
vendor: 9,452 bytes, lines 10156-10362
10156
10157      const refreshableEffect = keepTime(effect);
10158      this.effects.push(refreshableEffect);
10159      if (this.ready) this.effectsCleanups[this.effects.length - 1] = refreshableEffect(this);
10160      return this;
10161    }
10162
10163    revert() {
10164      clearTimeout(this.resizeTimeout);
10165      this.lines.length = this.words.length = this.chars.length = 0;
10166      this.resizeObserver.disconnect();
10167      // Make sure to revert the effects after disconnecting the resizeObserver to avoid triggering it in the process
10168      this.effectsCleanups.forEach(cleanup => isFnc(cleanup) ? cleanup(this) : cleanup.revert && cleanup.revert());
10169      this.$target.innerHTML = this.html;
10170      return this;
10171    }
10172
10173    /**
10174     * Recursively processes a node and its children
10175     * @param {Node} node
10176     */
10177    splitNode(node) {
10178      const wordTemplate = this.wordTemplate;
10179      const charTemplate = this.charTemplate;
10180      const includeSpaces = this.includeSpaces;
10181      const debug = this.debug;
10182      const nodeType = node.nodeType;
10183      if (nodeType === 3) {
10184        const nodeText = node.nodeValue;
10185        // If the nodeText is only whitespace, leave it as is
10186        if (nodeText.trim()) {
10187          const tempWords = [];
10188          const words = this.words;
10189          const chars = this.chars;
10190          const wordSegments = wordSegmenter.segment(nodeText);
10191          const $wordsFragment = doc.createDocumentFragment();
10192          let prevSeg = null;
10193          for (const wordSegment of wordSegments) {
10194            const segment = wordSegment.segment;
10195            const isWordLike = isSegmentWordLike(wordSegment);
10196            // Determine if this segment should be a new word, first segment always becomes a new word
10197            if (!prevSeg || (isWordLike && (prevSeg && (isSegmentWordLike(prevSeg))))) {
10198              tempWords.push(segment);
10199            } else {
10200              // Only concatenate if both current and previous are non-word-like and don't contain spaces
10201              const lastWordIndex = tempWords.length - 1;
10202              const lastWord = tempWords[lastWordIndex];
10203              if (!whiteSpaceGroupRgx.test(lastWord) && !whiteSpaceGroupRgx.test(segment)) {
10204                tempWords[lastWordIndex] += segment;
10205              } else {
10206                tempWords.push(segment);
10207              }
10208            }
10209            prevSeg = wordSegment;
10210          }
10211
10212          for (let i = 0, l = tempWords.length; i < l; i++) {
10213            const word = tempWords[i];
10214            if (!word.trim()) {
10215              // Preserve whitespace only if includeSpaces is false and if the current space is not the first node
10216              if (i && includeSpaces) continue;
10217              $wordsFragment.appendChild(doc.createTextNode(word));
10218            } else {
10219              const nextWord = tempWords[i + 1];
10220              const hasWordFollowingSpace = includeSpaces && nextWord && !nextWord.trim();
10221              const wordToProcess = word;
10222              const charSegments = charTemplate ? graphemeSegmenter.segment(wordToProcess) : null;
10223              const $charsFragment = charTemplate ? doc.createDocumentFragment() : doc.createTextNode(hasWordFollowingSpace ? word + '\xa0' : word);
10224              if (charTemplate) {
10225                const charSegmentsArray = [...charSegments];
10226                for (let j = 0, jl = charSegmentsArray.length; j < jl; j++) {
10227                  const charSegment = charSegmentsArray[j];
10228                  const isLastChar = j === jl - 1;
10229                  // If this is the last character and includeSpaces is true with a following space, append the space
10230                  const charText = isLastChar && hasWordFollowingSpace ? charSegment.segment + '\xa0' : charSegment.segment;
10231                  const $charNode = doc.createTextNode(charText);
10232                  processHTMLTemplate(charTemplate, chars, $charNode, /** @type {DocumentFragment} */($charsFragment), charType, debug, -1, words.length, chars.length);
10233                }
10234              }
10235              if (wordTemplate) {
10236                processHTMLTemplate(wordTemplate, words, $charsFragment, $wordsFragment, wordType, debug, -1, words.length, chars.length);
10237                // Chars elements must be re-parsed in the split() method if both words and chars are parsed
10238              } else if (charTemplate) {
10239                $wordsFragment.appendChild($charsFragment);
10240              } else {
10241                $wordsFragment.appendChild(doc.createTextNode(word));
10242              }
10243              // Skip the next iteration if we included a space
10244              if (hasWordFollowingSpace) i++;
10245            }
10246          }
10247          node.parentNode.replaceChild($wordsFragment, node);
10248        }
10249      } else if (nodeType === 1) {
10250        // Converting to an array is necessary to work around childNodes pottential mutation
10251        const childNodes = /** @type {Array<Node>} */([.../** @type {*} */(node.childNodes)]);
10252        for (let i = 0, l = childNodes.length; i < l; i++) this.splitNode(childNodes[i]);
10253      }
10254    }
10255
10256    /**
10257     * @param {Boolean} clearCache
10258     * @return {this}
10259     */
10260    split(clearCache = false) {
10261      const $el = this.$target;
10262      const isCached = !!this.cache && !clearCache;
10263      const lineTemplate = this.lineTemplate;
10264      const wordTemplate = this.wordTemplate;
10265      const charTemplate = this.charTemplate;
10266      const fontsReady = doc.fonts.status !== 'loading';
10267      const canSplitLines = lineTemplate && fontsReady;
10268      this.ready = !lineTemplate || fontsReady;
10269      if (canSplitLines || clearCache) {
10270        // No need to revert effects animations here since it's already taken care by the refreshable
10271        this.effectsCleanups.forEach(cleanup => isFnc(cleanup) && cleanup(this));
10272      }
10273      if (!isCached) {
10274        if (clearCache) {
10275          $el.innerHTML = this.html;
10276          this.words.length = this.chars.length = 0;
10277        }
10278        this.splitNode($el);
10279        this.cache = $el.innerHTML;
10280      }
10281      if (canSplitLines) {
10282        if (isCached) $el.innerHTML = this.cache;
10283        this.lines.length = 0;
10284        if (wordTemplate) this.words = getAllTopLevelElements($el, wordType);
10285      }
10286      // Always reparse characters after a line reset or if both words and chars are activated
10287      if (charTemplate && (canSplitLines || wordTemplate)) {
10288        this.chars = getAllTopLevelElements($el, charType);
10289      }
10290      // Words are used when lines only and prioritized over chars
10291      const elementsArray = this.words.length ? this.words : this.chars;
10292      let y, linesCount = 0;
10293      for (let i = 0, l = elementsArray.length; i < l; i++) {
10294        const $el = elementsArray[i];
10295        const { top, height } = $el.getBoundingClientRect();
10296        if (!isUnd(y) && top - y > height * .5) linesCount++;
10297        $el.setAttribute(dataLine, `${linesCount}`);
10298        const nested = $el.querySelectorAll(`[${dataLine}]`);
10299        let c = nested.length;
10300        while (c--) nested[c].setAttribute(dataLine, `${linesCount}`);
10301        y = top;
10302      }
10303      if (canSplitLines) {
10304        const linesFragment = doc.createDocumentFragment();
10305        const parents = new Set();
10306        const clones = [];
10307        for (let lineIndex = 0; lineIndex < linesCount + 1; lineIndex++) {
10308          const $clone = /** @type {HTMLElement} */($el.cloneNode(true));
10309          filterLineElements($clone, lineIndex, new Set()).forEach($el => {
10310            const $parent = $el.parentNode;
10311            if ($parent) {
10312              if ($el.nodeType === 1) parents.add(/** @type {HTMLElement} */($parent));
10313              $parent.removeChild($el);
10314            }
10315          });
10316          clones.push($clone);
10317        }
10318        parents.forEach(filterEmptyElements);
10319        for (let cloneIndex = 0, clonesLength = clones.length; cloneIndex < clonesLength; cloneIndex++) {
10320          processHTMLTemplate(lineTemplate, this.lines, clones[cloneIndex], linesFragment, lineType, this.debug, cloneIndex);
10321        }
10322        $el.innerHTML = '';
10323        $el.appendChild(linesFragment);
10324        if (wordTemplate) this.words = getAllTopLevelElements($el, wordType);
10325        if (charTemplate) this.chars = getAllTopLevelElements($el, charType);
10326      }
10327
10328      // Remove the word wrappers and clear the words array if lines split only
10329      if (this.linesOnly) {
10330        const words = this.words;
10331        let w = words.length;
10332        while (w--) {
10333          const $word = words[w];
10334          $word.replaceWith($word.textContent);
10335        }
10336        words.length = 0;
10337      }
10338      if (this.accessible && (canSplitLines || !isCached)) {
10339        const $accessible = doc.createElement('span');
10340        // Make the accessible element visually-hidden (https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html)
10341        $accessible.style.cssText = `position:absolute;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);width:1px;height:1px;white-space:nowrap;`;
10342        // $accessible.setAttribute('tabindex', '-1');
10343        $accessible.innerHTML = this.html;
10344        $el.insertBefore($accessible, $el.firstChild);
10345        this.lines.forEach(setAriaHidden);
10346        this.words.forEach(setAriaHidden);
10347        this.chars.forEach(setAriaHidden);
10348      }
10349      this.width = /** @type {HTMLElement} */($el).offsetWidth;
10350      if (canSplitLines || clearCache) {
10351        this.effects.forEach((effect, i) => this.effectsCleanups[i] = effect(this));
10352      }
10353      return this;
10354    }
10355
10356    refresh() {
10357      this.split(true);
10358    }
10359  }
10360
10361  /**
10362   * @param  {
10362HTMLElement|NodeList|String|Array<HTMLElement>} target
10363   * @param  {TextSplitterParams} [parameters]
10364   * @return {TextSplitter}
10365   */
10366  const splitText = (target, parameters) => new TextSplitter(target, parameters);
10367
10368  /**
10369   * @deprecated text.split() is deprecated, import splitText() directly, or text.splitText()
10370   *
10371   * @param  {HTMLElement|NodeList|String|Array<HTMLElement>} target
10372   * @param  {TextSplitterParams} [parameters]
10373   * @return {TextSplitter}
10374   */
10375  const split = (target, parameters) => {
10376    console.warn('text.split() is deprecated, import splitText() directly, or text.splitText()');
10377    return new TextSplitter(target, parameters);
10378  };
10379
10380  var index = /*#__PURE__*/Object.freeze({
10381    __proto__: null,
10382    TextSplitter: TextSplitter,
10383    split: split,
10384    splitText: splitText
10385  });
10386
10387  exports.$ = registerTargets;
10388  exports.Animatable = Animatable;
10389  exports.AutoLayout = AutoLayout;
10390  exports.Draggable = Draggable;
10391  exports.JSAnimation = JSAnimation;
10392  exports.Scope = Scope;
10393  exports.ScrollObserver = ScrollObserver;
10394  exports.Spring = Spring;
10395  exports.TextSplitter = TextSplitter;
10396  exports.Timeline = Timeline;
10397  exports.Timer = Timer;
10398  exports.WAAPIAnimation = WAAPIAnimation;
10399  exports.animate = animate;
10400  exports.clamp = clamp;
10401  exports.cleanInlineStyles = cleanInlineStyles;
10402  exports.createAnimatable = createAnimatable;
10403  exports.createDraggable = createDraggable;
10404  exports.createDrawable = createDrawable;
10405  exports.createLayout = createLayout;
10406  exports.createMotionPath = createMotionPath;
10407  exports.createScope = createScope;
10408  exports.createSeededRandom = createSeededRandom;
10409  exports.createSpring = createSpring;
10410  exports.createTimeline = createTimeline;
10411  exports.createTimer = createTimer;
10412  exports.cubicBezier = cubicBezier;
10413  exports.damp = damp;
10414  exports.degToRad = degToRad;
10415  exports.eases = eases;
10416  exports.easings = index$3;
10417  exports.engine = engine;
10418  exports.get = get;
10419  exports.irregular = irregular;
10420  exports.keepTime = keepTime;
10421  exports.lerp = lerp;
10422  exports.linear = linear;
10423  exports.mapRange = mapRange;
10424  exports.morphTo = morphTo;
10425  exports.onScroll = onScroll;
10426  exports.padEnd = padEnd;
10427  exports.padStart = padStart;
10428  exports.radToDeg = radToDeg;
10429  exports.random = random;
10430  exports.randomPick = randomPick;
10431  exports.remove = remove;
10432  exports.round = round;
10433  exports.roundPad = roundPad;
10434  exports.scrollContainers = scrollContainers;
10435  exports.set = set;
10436  exports.shuffle = shuffle;
10437  exports.snap = snap;
10438  exports.split = split;
10439  exports.splitText = splitText;
10440  exports.spring = spring;
10441  exports.stagger = stagger;
10442  exports.steps = steps;
10443  exports.svg = index$1;
10444  exports.sync = sync;
10445  exports.text = index;
10446  exports.utils = index$2;
10447  exports.waapi = waapi;
10448  exports.wrap = wrap;
10449
10450}));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.