animejs 4.0.2 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -47
- package/lib/anime.cjs +2 -2
- package/lib/anime.esm.js +860 -233
- package/lib/anime.esm.min.js +2 -2
- package/lib/anime.iife.js +2 -2
- package/lib/anime.iife.min.js +2 -2
- package/lib/anime.min.cjs +2 -2
- package/lib/anime.umd.js +2 -2
- package/lib/anime.umd.min.js +2 -2
- package/lib/gui/index.js +6341 -0
- package/package.json +1 -1
- package/types/index.d.ts +176 -117
- package/types/index.js +691 -158
package/lib/anime.esm.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* anime.js - ESM
|
|
3
|
-
* @version v4.0
|
|
3
|
+
* @version v4.1.0
|
|
4
4
|
* @author Julian Garnier
|
|
5
5
|
* @license MIT
|
|
6
6
|
* @copyright (c) 2025 Julian Garnier
|
|
7
7
|
* @see https://animejs.com
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
// Global types ///////////////////////////////////////////////////////////////
|
|
11
|
+
|
|
10
12
|
/**
|
|
11
13
|
* @typedef {Object} DefaultsParams
|
|
12
14
|
* @property {Number|String} [id]
|
|
@@ -36,61 +38,33 @@
|
|
|
36
38
|
/** @typedef {JSAnimation|Timeline} Renderable */
|
|
37
39
|
/** @typedef {Timer|Renderable} Tickable */
|
|
38
40
|
/** @typedef {Timer&JSAnimation&Timeline} CallbackArgument */
|
|
39
|
-
/** @typedef {Animatable|Tickable|Draggable|ScrollObserver|Scope} Revertible */
|
|
41
|
+
/** @typedef {Animatable|Tickable|Draggable|ScrollObserver|TextSplitter|Scope} Revertible */
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
* @typedef {Object} DraggableAxisParam
|
|
43
|
-
* @property {String} [mapTo]
|
|
44
|
-
* @property {TweenModifier} [modifier]
|
|
45
|
-
* @property {TweenComposition} [composition]
|
|
46
|
-
* @property {Number|Array<Number>|((draggable: Draggable) => Number|Array<Number>)} [snap]
|
|
47
|
-
*/
|
|
43
|
+
// Stagger types //////////////////////////////////////////////////////////////
|
|
48
44
|
|
|
49
45
|
/**
|
|
50
|
-
* @
|
|
51
|
-
* @
|
|
52
|
-
* @
|
|
46
|
+
* @callback StaggerFunction
|
|
47
|
+
* @param {Target} [target]
|
|
48
|
+
* @param {Number} [index]
|
|
49
|
+
* @param {Number} [length]
|
|
50
|
+
* @param {Timeline} [tl]
|
|
51
|
+
* @return {Number|String}
|
|
53
52
|
*/
|
|
54
53
|
|
|
55
54
|
/**
|
|
56
|
-
* @typedef
|
|
57
|
-
* @property {
|
|
58
|
-
* @property {
|
|
59
|
-
* @property {Boolean
|
|
60
|
-
* @property {
|
|
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|StaggerFunction} [use]
|
|
62
|
+
* @property {Number} [total]
|
|
63
|
+
* @property {EasingParam} [ease]
|
|
61
64
|
* @property {TweenModifier} [modifier]
|
|
62
|
-
* @property {Number|Array<Number>|((draggable: Draggable) => Number|Array<Number>)} [snap]
|
|
63
|
-
* @property {Number|Array<Number>|((draggable: Draggable) => Number|Array<Number>)} [containerPadding]
|
|
64
|
-
* @property {Number|((draggable: Draggable) => Number)} [containerFriction]
|
|
65
|
-
* @property {Number|((draggable: Draggable) => Number)} [releaseContainerFriction]
|
|
66
|
-
* @property {Number|((draggable: Draggable) => Number)} [dragSpeed]
|
|
67
|
-
* @property {Number|((draggable: Draggable) => Number)} [scrollSpeed]
|
|
68
|
-
* @property {Number|((draggable: Draggable) => Number)} [scrollThreshold]
|
|
69
|
-
* @property {Number|((draggable: Draggable) => Number)} [minVelocity]
|
|
70
|
-
* @property {Number|((draggable: Draggable) => Number)} [maxVelocity]
|
|
71
|
-
* @property {Number|((draggable: Draggable) => Number)} [velocityMultiplier]
|
|
72
|
-
* @property {Number} [releaseMass]
|
|
73
|
-
* @property {Number} [releaseStiffness]
|
|
74
|
-
* @property {Number} [releaseDamping]
|
|
75
|
-
* @property {Boolean} [releaseDamping]
|
|
76
|
-
* @property {EasingParam} [releaseEase]
|
|
77
|
-
* @property {Boolean|DraggableCursorParams|((draggable: Draggable) => Boolean|DraggableCursorParams)} [cursor]
|
|
78
|
-
* @property {Callback<Draggable>} [onGrab]
|
|
79
|
-
* @property {Callback<Draggable>} [onDrag]
|
|
80
|
-
* @property {Callback<Draggable>} [onRelease]
|
|
81
|
-
* @property {Callback<Draggable>} [onUpdate]
|
|
82
|
-
* @property {Callback<Draggable>} [onSettle]
|
|
83
|
-
* @property {Callback<Draggable>} [onSnap]
|
|
84
|
-
* @property {Callback<Draggable>} [onResize]
|
|
85
|
-
* @property {Callback<Draggable>} [onAfterResize]
|
|
86
65
|
*/
|
|
87
66
|
|
|
88
|
-
|
|
89
|
-
* @typedef {SVGGeometryElement & {
|
|
90
|
-
* setAttribute(name: 'draw', value: `${number} ${number}`): void;
|
|
91
|
-
* draw: `${number} ${number}`;
|
|
92
|
-
* }} DrawableSVGGeometry
|
|
93
|
-
*/
|
|
67
|
+
// Eases types ////////////////////////////////////////////////////////////////
|
|
94
68
|
|
|
95
69
|
/**
|
|
96
70
|
* @callback EasingFunction
|
|
@@ -118,21 +92,7 @@
|
|
|
118
92
|
/** @typedef {Array.<TargetSelector>|TargetSelector} TargetsParam */
|
|
119
93
|
/** @typedef {Array.<Target>} TargetsArray */
|
|
120
94
|
|
|
121
|
-
|
|
122
|
-
* @callback FunctionValue
|
|
123
|
-
* @param {Target} target - The animated target
|
|
124
|
-
* @param {Number} index - The target index
|
|
125
|
-
* @param {Number} length - The total number of animated targets
|
|
126
|
-
* @return {Number|String|TweenObjectValue|Array.<Number|String|TweenObjectValue>}
|
|
127
|
-
*/
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* @callback TweenModifier
|
|
131
|
-
* @param {Number} value - The animated value
|
|
132
|
-
* @return {Number|String}
|
|
133
|
-
*/
|
|
134
|
-
|
|
135
|
-
/** @typedef {[Number, Number, Number, Number]} ColorArray */
|
|
95
|
+
// Callback types ////////////////////////////////////////////////////////////
|
|
136
96
|
|
|
137
97
|
/**
|
|
138
98
|
* @template T
|
|
@@ -159,6 +119,46 @@
|
|
|
159
119
|
* @property {Callback<T>} [onRender]
|
|
160
120
|
*/
|
|
161
121
|
|
|
122
|
+
// Timer types ////////////////////////////////////////////////////////////////
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* @typedef {Object} TimerOptions
|
|
126
|
+
* @property {Number|String} [id]
|
|
127
|
+
* @property {TweenParamValue} [duration]
|
|
128
|
+
* @property {TweenParamValue} [delay]
|
|
129
|
+
* @property {Number} [loopDelay]
|
|
130
|
+
* @property {Boolean} [reversed]
|
|
131
|
+
* @property {Boolean} [alternate]
|
|
132
|
+
* @property {Boolean|Number} [loop]
|
|
133
|
+
* @property {Boolean|ScrollObserver} [autoplay]
|
|
134
|
+
* @property {Number} [frameRate]
|
|
135
|
+
* @property {Number} [playbackRate]
|
|
136
|
+
*/
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @typedef {TimerOptions & TickableCallbacks<Timer>} TimerParams
|
|
142
|
+
*/
|
|
143
|
+
|
|
144
|
+
// Tween types ////////////////////////////////////////////////////////////////
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @callback FunctionValue
|
|
148
|
+
* @param {Target} target - The animated target
|
|
149
|
+
* @param {Number} index - The target index
|
|
150
|
+
* @param {Number} length - The total number of animated targets
|
|
151
|
+
* @return {Number|String|TweenObjectValue|Array.<Number|String|TweenObjectValue>}
|
|
152
|
+
*/
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* @callback TweenModifier
|
|
156
|
+
* @param {Number} value - The animated value
|
|
157
|
+
* @return {Number|String}
|
|
158
|
+
*/
|
|
159
|
+
|
|
160
|
+
/** @typedef {[Number, Number, Number, Number]} ColorArray */
|
|
161
|
+
|
|
162
162
|
/**
|
|
163
163
|
* @typedef {Object} Tween
|
|
164
164
|
* @property {Number} id
|
|
@@ -212,25 +212,7 @@
|
|
|
212
212
|
/** @typedef {WeakMap.<Target, TweenLookups>} TweenReplaceLookups */
|
|
213
213
|
/** @typedef {Map.<Target, TweenLookups>} TweenAdditiveLookups */
|
|
214
214
|
|
|
215
|
-
|
|
216
|
-
* @typedef {Object} TimerOptions
|
|
217
|
-
* @property {Number|String} [id]
|
|
218
|
-
* @property {TweenParamValue} [duration]
|
|
219
|
-
* @property {TweenParamValue} [delay]
|
|
220
|
-
* @property {Number} [loopDelay]
|
|
221
|
-
* @property {Boolean} [reversed]
|
|
222
|
-
* @property {Boolean} [alternate]
|
|
223
|
-
* @property {Boolean|Number} [loop]
|
|
224
|
-
* @property {Boolean|ScrollObserver} [autoplay]
|
|
225
|
-
* @property {Number} [frameRate]
|
|
226
|
-
* @property {Number} [playbackRate]
|
|
227
|
-
*/
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* @typedef {TimerOptions & TickableCallbacks<Timer>} TimerParams
|
|
233
|
-
*/
|
|
215
|
+
// Animation types ////////////////////////////////////////////////////////////
|
|
234
216
|
|
|
235
217
|
/**
|
|
236
218
|
* @typedef {Number|String|FunctionValue} TweenParamValue
|
|
@@ -304,6 +286,8 @@
|
|
|
304
286
|
* @typedef {Record<String, TweenOptions | Callback<JSAnimation> | TweenModifier | boolean | PercentageKeyframes | DurationKeyframes | ScrollObserver> & TimerOptions & AnimationOptions & TweenParamsOptions & TickableCallbacks<JSAnimation> & RenderableCallbacks<JSAnimation>} AnimationParams
|
|
305
287
|
*/
|
|
306
288
|
|
|
289
|
+
// Timeline types /////////////////////////////////////////////////////////////
|
|
290
|
+
|
|
307
291
|
/**
|
|
308
292
|
* @typedef {Object} TimelineOptions
|
|
309
293
|
* @property {DefaultsParams} [defaults]
|
|
@@ -314,6 +298,8 @@
|
|
|
314
298
|
* @typedef {TimerOptions & TimelineOptions & TickableCallbacks<Timeline> & RenderableCallbacks<Timeline>} TimelineParams
|
|
315
299
|
*/
|
|
316
300
|
|
|
301
|
+
// Animatable types ///////////////////////////////////////////////////////////
|
|
302
|
+
|
|
317
303
|
/**
|
|
318
304
|
* @callback AnimatablePropertySetter
|
|
319
305
|
* @param {Number|Array.<Number>} to
|
|
@@ -348,6 +334,136 @@
|
|
|
348
334
|
* @typedef {Record<String, TweenParamValue | EasingParam | TweenModifier | TweenComposition | AnimatablePropertyParamsOptions> & AnimatablePropertyParamsOptions} AnimatableParams
|
|
349
335
|
*/
|
|
350
336
|
|
|
337
|
+
// Scope types ////////////////////////////////////////////////////////////////
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* @typedef {Object} ReactRef
|
|
341
|
+
* @property {HTMLElement|SVGElement|null} [current]
|
|
342
|
+
*/
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* @typedef {Object} AngularRef
|
|
346
|
+
* @property {HTMLElement|SVGElement} [nativeElement]
|
|
347
|
+
*/
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* @typedef {Object} ScopeParams
|
|
351
|
+
* @property {DOMTargetSelector|ReactRef|AngularRef} [root]
|
|
352
|
+
* @property {DefaultsParams} [defaults]
|
|
353
|
+
* @property {Record<String, String>} [mediaQueries]
|
|
354
|
+
*/
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* @template T
|
|
358
|
+
* @callback ScopedCallback
|
|
359
|
+
* @param {Scope} scope
|
|
360
|
+
* @return {T}
|
|
361
|
+
*/
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* @callback ScopeCleanupCallback
|
|
365
|
+
* @param {Scope} [scope]
|
|
366
|
+
*/
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* @callback ScopeConstructorCallback
|
|
370
|
+
* @param {Scope} [scope]
|
|
371
|
+
* @return {ScopeCleanupCallback|void}
|
|
372
|
+
*/
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* @callback ScopeMethod
|
|
376
|
+
* @param {...*} args
|
|
377
|
+
* @return {ScopeCleanupCallback|void}
|
|
378
|
+
*/
|
|
379
|
+
|
|
380
|
+
// Draggable types ////////////////////////////////////////////////////////////
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* @typedef {Object} DraggableAxisParam
|
|
384
|
+
* @property {String} [mapTo]
|
|
385
|
+
* @property {TweenModifier} [modifier]
|
|
386
|
+
* @property {TweenComposition} [composition]
|
|
387
|
+
* @property {Number|Array<Number>|((draggable: Draggable) => Number|Array<Number>)} [snap]
|
|
388
|
+
*/
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* @typedef {Object} DraggableCursorParams
|
|
392
|
+
* @property {String} [onHover]
|
|
393
|
+
* @property {String} [onGrab]
|
|
394
|
+
*/
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* @typedef {Object} DraggableParams
|
|
398
|
+
* @property {DOMTargetSelector} [trigger]
|
|
399
|
+
* @property {DOMTargetSelector|Array<Number>|((draggable: Draggable) => DOMTargetSelector|Array<Number>)} [container]
|
|
400
|
+
* @property {Boolean|DraggableAxisParam} [x]
|
|
401
|
+
* @property {Boolean|DraggableAxisParam} [y]
|
|
402
|
+
* @property {TweenModifier} [modifier]
|
|
403
|
+
* @property {Number|Array<Number>|((draggable: Draggable) => Number|Array<Number>)} [snap]
|
|
404
|
+
* @property {Number|Array<Number>|((draggable: Draggable) => Number|Array<Number>)} [containerPadding]
|
|
405
|
+
* @property {Number|((draggable: Draggable) => Number)} [containerFriction]
|
|
406
|
+
* @property {Number|((draggable: Draggable) => Number)} [releaseContainerFriction]
|
|
407
|
+
* @property {Number|((draggable: Draggable) => Number)} [dragSpeed]
|
|
408
|
+
* @property {Number|((draggable: Draggable) => Number)} [scrollSpeed]
|
|
409
|
+
* @property {Number|((draggable: Draggable) => Number)} [scrollThreshold]
|
|
410
|
+
* @property {Number|((draggable: Draggable) => Number)} [minVelocity]
|
|
411
|
+
* @property {Number|((draggable: Draggable) => Number)} [maxVelocity]
|
|
412
|
+
* @property {Number|((draggable: Draggable) => Number)} [velocityMultiplier]
|
|
413
|
+
* @property {Number} [releaseMass]
|
|
414
|
+
* @property {Number} [releaseStiffness]
|
|
415
|
+
* @property {Number} [releaseDamping]
|
|
416
|
+
* @property {Boolean} [releaseDamping]
|
|
417
|
+
* @property {EasingParam} [releaseEase]
|
|
418
|
+
* @property {Boolean|DraggableCursorParams|((draggable: Draggable) => Boolean|DraggableCursorParams)} [cursor]
|
|
419
|
+
* @property {Callback<Draggable>} [onGrab]
|
|
420
|
+
* @property {Callback<Draggable>} [onDrag]
|
|
421
|
+
* @property {Callback<Draggable>} [onRelease]
|
|
422
|
+
* @property {Callback<Draggable>} [onUpdate]
|
|
423
|
+
* @property {Callback<Draggable>} [onSettle]
|
|
424
|
+
* @property {Callback<Draggable>} [onSnap]
|
|
425
|
+
* @property {Callback<Draggable>} [onResize]
|
|
426
|
+
* @property {Callback<Draggable>} [onAfterResize]
|
|
427
|
+
*/
|
|
428
|
+
|
|
429
|
+
// Text types /////////////////////////////////////////////////////////////////
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* @typedef {Object} splitTemplateParams
|
|
433
|
+
* @property {false|String} [class]
|
|
434
|
+
* @property {Boolean|'hidden'|'clip'|'visible'|'scroll'|'auto'} [wrap]
|
|
435
|
+
* @property {Boolean|'top'|'right'|'bottom'|'left'|'center'} [clone]
|
|
436
|
+
*/
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* @typedef {Boolean|String} SplitValue
|
|
440
|
+
*/
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* @callback SplitFunctionValue
|
|
444
|
+
* @param {Node|HTMLElement} [value]
|
|
445
|
+
* @return String
|
|
446
|
+
*/
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* @typedef {Object} TextSplitterParams
|
|
450
|
+
* @property {SplitValue|splitTemplateParams|SplitFunctionValue} [lines]
|
|
451
|
+
* @property {SplitValue|splitTemplateParams|SplitFunctionValue} [words]
|
|
452
|
+
* @property {SplitValue|splitTemplateParams|SplitFunctionValue} [chars]
|
|
453
|
+
* @property {Boolean} [accessible]
|
|
454
|
+
* @property {Boolean} [includeSpaces]
|
|
455
|
+
* @property {Boolean} [debug]
|
|
456
|
+
*/
|
|
457
|
+
|
|
458
|
+
// SVG types //////////////////////////////////////////////////////////////////
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* @typedef {SVGGeometryElement & {
|
|
462
|
+
* setAttribute(name: 'draw', value: `${number} ${number}`): void;
|
|
463
|
+
* draw: `${number} ${number}`;
|
|
464
|
+
* }} DrawableSVGGeometry
|
|
465
|
+
*/
|
|
466
|
+
|
|
351
467
|
|
|
352
468
|
// Environments
|
|
353
469
|
|
|
@@ -412,11 +528,13 @@ const maxFps = 120;
|
|
|
412
528
|
// Strings
|
|
413
529
|
|
|
414
530
|
const emptyString = '';
|
|
415
|
-
const shortTransforms =
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
531
|
+
const shortTransforms = /*#__PURE__*/ (() => {
|
|
532
|
+
const map = new Map();
|
|
533
|
+
map.set('x', 'translateX');
|
|
534
|
+
map.set('y', 'translateY');
|
|
535
|
+
map.set('z', 'translateZ');
|
|
536
|
+
return map;
|
|
537
|
+
})();
|
|
420
538
|
|
|
421
539
|
const validTransforms = [
|
|
422
540
|
'translateX',
|
|
@@ -438,7 +556,7 @@ const validTransforms = [
|
|
|
438
556
|
'matrix3d',
|
|
439
557
|
];
|
|
440
558
|
|
|
441
|
-
const transformsFragmentStrings = validTransforms.reduce((a, v) => ({...a, [v]: v + '('}), {});
|
|
559
|
+
const transformsFragmentStrings = /*#__PURE__*/ validTransforms.reduce((a, v) => ({...a, [v]: v + '('}), {});
|
|
442
560
|
|
|
443
561
|
// Functions
|
|
444
562
|
|
|
@@ -489,13 +607,16 @@ const defaults = {
|
|
|
489
607
|
onRender: noop,
|
|
490
608
|
};
|
|
491
609
|
|
|
610
|
+
const scope = {
|
|
611
|
+
/** @type {Scope} */
|
|
612
|
+
current: null,
|
|
613
|
+
/** @type {Document|DOMTarget} */
|
|
614
|
+
root: doc,
|
|
615
|
+
};
|
|
616
|
+
|
|
492
617
|
const globals = {
|
|
493
618
|
/** @type {DefaultsParams} */
|
|
494
619
|
defaults,
|
|
495
|
-
/** @type {Document|DOMTarget} */
|
|
496
|
-
root: doc,
|
|
497
|
-
/** @type {Scope} */
|
|
498
|
-
scope: null,
|
|
499
620
|
/** @type {Number} */
|
|
500
621
|
precision: 4,
|
|
501
622
|
/** @type {Number} */
|
|
@@ -504,7 +625,7 @@ const globals = {
|
|
|
504
625
|
tickThreshold: 200,
|
|
505
626
|
};
|
|
506
627
|
|
|
507
|
-
const globalVersions = { version: '4.0
|
|
628
|
+
const globalVersions = { version: '4.1.0', engine: null };
|
|
508
629
|
|
|
509
630
|
if (isBrowser) {
|
|
510
631
|
if (!win.AnimeJS) win.AnimeJS = [];
|
|
@@ -623,6 +744,25 @@ const snap = (v, increment) => isArr(increment) ? increment.reduce((closest, cv)
|
|
|
623
744
|
*/
|
|
624
745
|
const interpolate = (start, end, progress) => start + (end - start) * progress;
|
|
625
746
|
|
|
747
|
+
/**
|
|
748
|
+
* @param {Number} min
|
|
749
|
+
* @param {Number} max
|
|
750
|
+
* @param {Number} [decimalLength]
|
|
751
|
+
* @return {Number}
|
|
752
|
+
*/
|
|
753
|
+
const random = (min, max, decimalLength) => { const m = 10 ** (decimalLength || 0); return floor((Math.random() * (max - min + (1 / m)) + min) * m) / m };
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* Adapted from https://bost.ocks.org/mike/shuffle/
|
|
757
|
+
* @param {Array} items
|
|
758
|
+
* @return {Array}
|
|
759
|
+
*/
|
|
760
|
+
const shuffle = items => {
|
|
761
|
+
let m = items.length, t, i;
|
|
762
|
+
while (m) { i = random(0, --m); t = items[m]; items[m] = items[i]; items[i] = t; }
|
|
763
|
+
return items;
|
|
764
|
+
};
|
|
765
|
+
|
|
626
766
|
/**
|
|
627
767
|
* @param {Number} v
|
|
628
768
|
* @return {Number}
|
|
@@ -719,6 +859,32 @@ const addChild = (parent, child, sortMethod, prevProp = '_prev', nextProp = '_ne
|
|
|
719
859
|
child[nextProp] = next;
|
|
720
860
|
};
|
|
721
861
|
|
|
862
|
+
/**
|
|
863
|
+
* @param {(...args: any[]) => Tickable | ((...args: any[]) => void)} constructor
|
|
864
|
+
* @return {(...args: any[]) => Tickable | ((...args: any[]) => void)}
|
|
865
|
+
*/
|
|
866
|
+
const createRefreshable = constructor => {
|
|
867
|
+
/** @type {Tickable} */
|
|
868
|
+
let tracked;
|
|
869
|
+
return (...args) => {
|
|
870
|
+
let currentIteration, currentIterationProgress, reversed, alternate;
|
|
871
|
+
if (tracked) {
|
|
872
|
+
currentIteration = tracked.currentIteration;
|
|
873
|
+
currentIterationProgress = tracked.iterationProgress;
|
|
874
|
+
reversed = tracked.reversed;
|
|
875
|
+
alternate = tracked._alternate;
|
|
876
|
+
tracked.revert();
|
|
877
|
+
}
|
|
878
|
+
const cleanup = constructor(...args);
|
|
879
|
+
if (cleanup && !isFnc(cleanup) && cleanup.revert) tracked = cleanup;
|
|
880
|
+
if (!isUnd(currentIterationProgress)) {
|
|
881
|
+
/** @type {Tickable} */(tracked).currentIteration = currentIteration;
|
|
882
|
+
/** @type {Tickable} */(tracked).iterationProgress = (alternate ? !(currentIteration % 2) ? reversed : !reversed : reversed) ? 1 - currentIterationProgress : currentIterationProgress;
|
|
883
|
+
}
|
|
884
|
+
return cleanup || noop;
|
|
885
|
+
}
|
|
886
|
+
};
|
|
887
|
+
|
|
722
888
|
/*
|
|
723
889
|
* Base class to control framerate and playback rate.
|
|
724
890
|
* Inherited by Engine, Timer, Animation and Timeline.
|
|
@@ -1227,8 +1393,8 @@ const addAdditiveAnimation = lookups => {
|
|
|
1227
1393
|
return animation;
|
|
1228
1394
|
};
|
|
1229
1395
|
|
|
1230
|
-
const engineTickMethod = isBrowser ? requestAnimationFrame : setImmediate;
|
|
1231
|
-
const engineCancelMethod = isBrowser ? cancelAnimationFrame : clearImmediate;
|
|
1396
|
+
const engineTickMethod = /*#__PURE__*/ (() => isBrowser ? requestAnimationFrame : setImmediate)();
|
|
1397
|
+
const engineCancelMethod = /*#__PURE__*/ (() => isBrowser ? cancelAnimationFrame : clearImmediate)();
|
|
1232
1398
|
|
|
1233
1399
|
class Engine extends Clock {
|
|
1234
1400
|
|
|
@@ -1402,7 +1568,7 @@ const parseInlineTransforms = (target, propName, animationInlineStyles) => {
|
|
|
1402
1568
|
* @return {NodeList|HTMLCollection}
|
|
1403
1569
|
*/
|
|
1404
1570
|
function getNodeList(v) {
|
|
1405
|
-
const n = isStr(v) ?
|
|
1571
|
+
const n = isStr(v) ? scope.root.querySelectorAll(v) : v;
|
|
1406
1572
|
if (n instanceof NodeList || n instanceof HTMLCollection) return n;
|
|
1407
1573
|
}
|
|
1408
1574
|
|
|
@@ -2335,7 +2501,7 @@ class Timer extends Clock {
|
|
|
2335
2501
|
onUpdate,
|
|
2336
2502
|
} = parameters;
|
|
2337
2503
|
|
|
2338
|
-
if (
|
|
2504
|
+
if (scope.current) scope.current.register(this);
|
|
2339
2505
|
|
|
2340
2506
|
const timerInitTime = parent ? 0 : engine._elapsedTime;
|
|
2341
2507
|
const timerDefaults = parent ? parent.defaults : globals.defaults;
|
|
@@ -2465,7 +2631,7 @@ class Timer extends Clock {
|
|
|
2465
2631
|
}
|
|
2466
2632
|
|
|
2467
2633
|
get progress() {
|
|
2468
|
-
return clamp(round(this._currentTime / this.duration,
|
|
2634
|
+
return clamp(round(this._currentTime / this.duration, 10), 0, 1);
|
|
2469
2635
|
}
|
|
2470
2636
|
|
|
2471
2637
|
/** @param {Number} progress */
|
|
@@ -2474,7 +2640,7 @@ class Timer extends Clock {
|
|
|
2474
2640
|
}
|
|
2475
2641
|
|
|
2476
2642
|
get iterationProgress() {
|
|
2477
|
-
return clamp(round(this._iterationTime / this.iterationDuration,
|
|
2643
|
+
return clamp(round(this._iterationTime / this.iterationDuration, 10), 0, 1);
|
|
2478
2644
|
}
|
|
2479
2645
|
|
|
2480
2646
|
/** @param {Number} progress */
|
|
@@ -3734,12 +3900,13 @@ class JSAnimation extends Timer {
|
|
|
3734
3900
|
*/
|
|
3735
3901
|
refresh() {
|
|
3736
3902
|
forEachChildren(this, (/** @type {Tween} */tween) => {
|
|
3737
|
-
const
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3903
|
+
const tweenFunc = tween._func;
|
|
3904
|
+
if (tweenFunc) {
|
|
3905
|
+
const ogValue = getOriginalAnimatableValue(tween.target, tween.property, tween._tweenType);
|
|
3906
|
+
decomposeRawValue(ogValue, decomposedOriginalValue);
|
|
3907
|
+
decomposeRawValue(tweenFunc(), toTargetObject);
|
|
3908
|
+
tween._fromNumbers = cloneArray(decomposedOriginalValue.d);
|
|
3909
|
+
tween._fromNumber = decomposedOriginalValue.n;
|
|
3743
3910
|
tween._toNumbers = cloneArray(toTargetObject.d);
|
|
3744
3911
|
tween._strings = cloneArray(toTargetObject.s);
|
|
3745
3912
|
tween._toNumber = toTargetObject.n;
|
|
@@ -3898,30 +4065,9 @@ const commonDefaultPXProperties = [
|
|
|
3898
4065
|
...transformsShorthands
|
|
3899
4066
|
];
|
|
3900
4067
|
|
|
3901
|
-
const validIndividualTransforms = [...transformsShorthands, ...validTransforms.filter(t => ['X', 'Y', 'Z'].some(axis => t.endsWith(axis)))];
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
let transformsPropertiesRegistered = isBrowser && (isUnd(CSS) || !Object.hasOwnProperty.call(CSS, 'registerProperty'));
|
|
3905
|
-
|
|
3906
|
-
const registerTransformsProperties = () => {
|
|
3907
|
-
if (transformsPropertiesRegistered) return;
|
|
3908
|
-
validTransforms.forEach(t => {
|
|
3909
|
-
const isSkew = stringStartsWith(t, 'skew');
|
|
3910
|
-
const isScale = stringStartsWith(t, 'scale');
|
|
3911
|
-
const isRotate = stringStartsWith(t, 'rotate');
|
|
3912
|
-
const isTranslate = stringStartsWith(t, 'translate');
|
|
3913
|
-
const isAngle = isRotate || isSkew;
|
|
3914
|
-
const syntax = isAngle ? '<angle>' : isScale ? "<number>" : isTranslate ? "<length-percentage>" : "*";
|
|
3915
|
-
try {
|
|
3916
|
-
CSS.registerProperty({
|
|
3917
|
-
name: '--' + t,
|
|
3918
|
-
syntax,
|
|
3919
|
-
inherits: false,
|
|
3920
|
-
initialValue: isTranslate ? '0px' : isAngle ? '0deg' : isScale ? '1' : '0',
|
|
3921
|
-
});
|
|
3922
|
-
} catch {} });
|
|
3923
|
-
transformsPropertiesRegistered = true;
|
|
3924
|
-
};
|
|
4068
|
+
const validIndividualTransforms = /*#__PURE__*/ (() => [...transformsShorthands, ...validTransforms.filter(t => ['X', 'Y', 'Z'].some(axis => t.endsWith(axis)))])();
|
|
4069
|
+
|
|
4070
|
+
let transformsPropertiesRegistered = null;
|
|
3925
4071
|
|
|
3926
4072
|
const WAAPIAnimationsLookups = {
|
|
3927
4073
|
_head: null,
|
|
@@ -4032,9 +4178,31 @@ class WAAPIAnimation {
|
|
|
4032
4178
|
*/
|
|
4033
4179
|
constructor(targets, params) {
|
|
4034
4180
|
|
|
4035
|
-
if (
|
|
4181
|
+
if (scope.current) scope.current.register(this);
|
|
4036
4182
|
|
|
4037
|
-
|
|
4183
|
+
// Skip the registration and fallback to no animation in case CSS.registerProperty is not supported
|
|
4184
|
+
if (isNil(transformsPropertiesRegistered)) {
|
|
4185
|
+
if (isBrowser && (isUnd(CSS) || !Object.hasOwnProperty.call(CSS, 'registerProperty'))) {
|
|
4186
|
+
transformsPropertiesRegistered = false;
|
|
4187
|
+
} else {
|
|
4188
|
+
validTransforms.forEach(t => {
|
|
4189
|
+
const isSkew = stringStartsWith(t, 'skew');
|
|
4190
|
+
const isScale = stringStartsWith(t, 'scale');
|
|
4191
|
+
const isRotate = stringStartsWith(t, 'rotate');
|
|
4192
|
+
const isTranslate = stringStartsWith(t, 'translate');
|
|
4193
|
+
const isAngle = isRotate || isSkew;
|
|
4194
|
+
const syntax = isAngle ? '<angle>' : isScale ? "<number>" : isTranslate ? "<length-percentage>" : "*";
|
|
4195
|
+
try {
|
|
4196
|
+
CSS.registerProperty({
|
|
4197
|
+
name: '--' + t,
|
|
4198
|
+
syntax,
|
|
4199
|
+
inherits: false,
|
|
4200
|
+
initialValue: isTranslate ? '0px' : isAngle ? '0deg' : isScale ? '1' : '0',
|
|
4201
|
+
});
|
|
4202
|
+
} catch {} });
|
|
4203
|
+
transformsPropertiesRegistered = true;
|
|
4204
|
+
}
|
|
4205
|
+
}
|
|
4038
4206
|
|
|
4039
4207
|
const parsedTargets = registerTargets(targets);
|
|
4040
4208
|
const targetsLength = parsedTargets.length;
|
|
@@ -4488,12 +4656,10 @@ const remove = (targets, renderable, propertyName) => {
|
|
|
4488
4656
|
};
|
|
4489
4657
|
|
|
4490
4658
|
/**
|
|
4491
|
-
* @param {
|
|
4492
|
-
* @
|
|
4493
|
-
* @param {Number} [decimalLength]
|
|
4494
|
-
* @return {Number}
|
|
4659
|
+
* @param {(...args: any[]) => Tickable} constructor
|
|
4660
|
+
* @return {(...args: any[]) => Tickable}
|
|
4495
4661
|
*/
|
|
4496
|
-
const
|
|
4662
|
+
const keepTime = createRefreshable;
|
|
4497
4663
|
|
|
4498
4664
|
/**
|
|
4499
4665
|
* @param {String|Array} items
|
|
@@ -4501,17 +4667,6 @@ const random = (min, max, decimalLength) => { const m = 10 ** (decimalLength ||
|
|
|
4501
4667
|
*/
|
|
4502
4668
|
const randomPick = items => items[random(0, items.length - 1)];
|
|
4503
4669
|
|
|
4504
|
-
/**
|
|
4505
|
-
* Adapted from https://bost.ocks.org/mike/shuffle/
|
|
4506
|
-
* @param {Array} items
|
|
4507
|
-
* @return {Array}
|
|
4508
|
-
*/
|
|
4509
|
-
const shuffle = items => {
|
|
4510
|
-
let m = items.length, t, i;
|
|
4511
|
-
while (m) { i = random(0, --m); t = items[m]; items[m] = items[i]; items[i] = t; }
|
|
4512
|
-
return items;
|
|
4513
|
-
};
|
|
4514
|
-
|
|
4515
4670
|
/**
|
|
4516
4671
|
* @param {Number|String} v
|
|
4517
4672
|
* @param {Number} decimalLength
|
|
@@ -4706,6 +4861,7 @@ const utils = {
|
|
|
4706
4861
|
shuffle,
|
|
4707
4862
|
lerp,
|
|
4708
4863
|
sync,
|
|
4864
|
+
keepTime,
|
|
4709
4865
|
clamp: /** @type {typeof clamp & ChainedClamp} */(makeChainable(clamp)),
|
|
4710
4866
|
round: /** @type {typeof round & ChainedRound} */(makeChainable(round)),
|
|
4711
4867
|
snap: /** @type {typeof snap & ChainedSnap} */(makeChainable(snap)),
|
|
@@ -5045,7 +5201,7 @@ class Animatable {
|
|
|
5045
5201
|
* @param {AnimatableParams} parameters
|
|
5046
5202
|
*/
|
|
5047
5203
|
constructor(targets, parameters) {
|
|
5048
|
-
if (
|
|
5204
|
+
if (scope.current) scope.current.register(this);
|
|
5049
5205
|
/** @type {AnimationParams} */
|
|
5050
5206
|
const globalParams = {};
|
|
5051
5207
|
const properties = {};
|
|
@@ -5381,7 +5537,7 @@ class Draggable {
|
|
|
5381
5537
|
*/
|
|
5382
5538
|
constructor(target, parameters = {}) {
|
|
5383
5539
|
if (!target) return;
|
|
5384
|
-
if (
|
|
5540
|
+
if (scope.current) scope.current.register(this);
|
|
5385
5541
|
const paramX = parameters.x;
|
|
5386
5542
|
const paramY = parameters.y;
|
|
5387
5543
|
const trigger = parameters.trigger;
|
|
@@ -6442,44 +6598,10 @@ const createDraggable = (target, parameters) => new Draggable(target, parameters
|
|
|
6442
6598
|
|
|
6443
6599
|
|
|
6444
6600
|
|
|
6445
|
-
/**
|
|
6446
|
-
* @typedef {Object} ReactRef
|
|
6447
|
-
* @property {HTMLElement|SVGElement|null} [current]
|
|
6448
|
-
*/
|
|
6449
|
-
|
|
6450
|
-
/**
|
|
6451
|
-
* @typedef {Object} AngularRef
|
|
6452
|
-
* @property {HTMLElement|SVGElement} [nativeElement]
|
|
6453
|
-
*/
|
|
6454
|
-
|
|
6455
|
-
/**
|
|
6456
|
-
* @typedef {Object} ScopeParams
|
|
6457
|
-
* @property {DOMTargetSelector|ReactRef|AngularRef} [root]
|
|
6458
|
-
* @property {DefaultsParams} [defaults]
|
|
6459
|
-
* @property {Record<String, String>} [mediaQueries]
|
|
6460
|
-
*/
|
|
6461
|
-
|
|
6462
|
-
/**
|
|
6463
|
-
* @callback ScopeCleanup
|
|
6464
|
-
* @param {Scope} [scope]
|
|
6465
|
-
*/
|
|
6466
|
-
|
|
6467
|
-
/**
|
|
6468
|
-
* @callback ScopeConstructor
|
|
6469
|
-
* @param {Scope} [scope]
|
|
6470
|
-
* @return {ScopeCleanup|void}
|
|
6471
|
-
*/
|
|
6472
|
-
|
|
6473
|
-
/**
|
|
6474
|
-
* @callback ScopeMethod
|
|
6475
|
-
* @param {...*} args
|
|
6476
|
-
* @return {ScopeCleanup|void}
|
|
6477
|
-
*/
|
|
6478
|
-
|
|
6479
6601
|
class Scope {
|
|
6480
6602
|
/** @param {ScopeParams} [parameters] */
|
|
6481
6603
|
constructor(parameters = {}) {
|
|
6482
|
-
if (
|
|
6604
|
+
if (scope.current) scope.current.register(this);
|
|
6483
6605
|
const rootParam = parameters.root;
|
|
6484
6606
|
/** @type {Document|DOMTarget} */
|
|
6485
6607
|
let root = doc;
|
|
@@ -6496,13 +6618,23 @@ class Scope {
|
|
|
6496
6618
|
this.defaults = scopeDefaults ? mergeObjects(scopeDefaults, globalDefault) : globalDefault;
|
|
6497
6619
|
/** @type {Document|DOMTarget} */
|
|
6498
6620
|
this.root = root;
|
|
6499
|
-
/** @type {Array<
|
|
6621
|
+
/** @type {Array<ScopeConstructorCallback>} */
|
|
6500
6622
|
this.constructors = [];
|
|
6501
|
-
/** @type {Array<
|
|
6623
|
+
/** @type {Array<ScopeCleanupCallback>} */
|
|
6502
6624
|
this.revertConstructors = [];
|
|
6503
6625
|
/** @type {Array<Revertible>} */
|
|
6504
6626
|
this.revertibles = [];
|
|
6505
|
-
/** @type {
|
|
6627
|
+
/** @type {Array<ScopeConstructorCallback | ((scope: this) => Tickable)>} */
|
|
6628
|
+
this.constructorsOnce = [];
|
|
6629
|
+
/** @type {Array<ScopeCleanupCallback>} */
|
|
6630
|
+
this.revertConstructorsOnce = [];
|
|
6631
|
+
/** @type {Array<Revertible>} */
|
|
6632
|
+
this.revertiblesOnce = [];
|
|
6633
|
+
/** @type {Boolean} */
|
|
6634
|
+
this.once = false;
|
|
6635
|
+
/** @type {Number} */
|
|
6636
|
+
this.onceIndex = 0;
|
|
6637
|
+
/** @type {Record<String, ScopeMethod>} */
|
|
6506
6638
|
this.methods = {};
|
|
6507
6639
|
/** @type {Record<String, Boolean>} */
|
|
6508
6640
|
this.matches = {};
|
|
@@ -6520,25 +6652,30 @@ class Scope {
|
|
|
6520
6652
|
}
|
|
6521
6653
|
|
|
6522
6654
|
/**
|
|
6523
|
-
* @
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
|
|
6528
|
-
|
|
6655
|
+
* @param {Revertible} revertible
|
|
6656
|
+
*/
|
|
6657
|
+
register(revertible) {
|
|
6658
|
+
const store = this.once ? this.revertiblesOnce : this.revertibles;
|
|
6659
|
+
store.push(revertible);
|
|
6660
|
+
}
|
|
6661
|
+
|
|
6662
|
+
/**
|
|
6663
|
+
* @template T
|
|
6664
|
+
* @param {ScopedCallback<T>} cb
|
|
6665
|
+
* @return {T}
|
|
6529
6666
|
*/
|
|
6530
6667
|
execute(cb) {
|
|
6531
|
-
let activeScope =
|
|
6532
|
-
let activeRoot =
|
|
6668
|
+
let activeScope = scope.current;
|
|
6669
|
+
let activeRoot = scope.root;
|
|
6533
6670
|
let activeDefaults = globals.defaults;
|
|
6534
|
-
|
|
6535
|
-
|
|
6671
|
+
scope.current = this;
|
|
6672
|
+
scope.root = this.root;
|
|
6536
6673
|
globals.defaults = this.defaults;
|
|
6537
6674
|
const mqs = this.mediaQueryLists;
|
|
6538
6675
|
for (let mq in mqs) this.matches[mq] = mqs[mq].matches;
|
|
6539
6676
|
const returned = cb(this);
|
|
6540
|
-
|
|
6541
|
-
|
|
6677
|
+
scope.current = activeScope;
|
|
6678
|
+
scope.root = activeRoot;
|
|
6542
6679
|
globals.defaults = activeDefaults;
|
|
6543
6680
|
return returned;
|
|
6544
6681
|
}
|
|
@@ -6547,6 +6684,7 @@ class Scope {
|
|
|
6547
6684
|
* @return {this}
|
|
6548
6685
|
*/
|
|
6549
6686
|
refresh() {
|
|
6687
|
+
this.onceIndex = 0;
|
|
6550
6688
|
this.execute(() => {
|
|
6551
6689
|
let i = this.revertibles.length;
|
|
6552
6690
|
let y = this.revertConstructors.length;
|
|
@@ -6554,9 +6692,9 @@ class Scope {
|
|
|
6554
6692
|
while (y--) this.revertConstructors[y](this);
|
|
6555
6693
|
this.revertibles.length = 0;
|
|
6556
6694
|
this.revertConstructors.length = 0;
|
|
6557
|
-
this.constructors.forEach( constructor => {
|
|
6695
|
+
this.constructors.forEach((/** @type {ScopeConstructorCallback} */constructor) => {
|
|
6558
6696
|
const revertConstructor = constructor(this);
|
|
6559
|
-
if (revertConstructor) {
|
|
6697
|
+
if (isFnc(revertConstructor)) {
|
|
6560
6698
|
this.revertConstructors.push(revertConstructor);
|
|
6561
6699
|
}
|
|
6562
6700
|
});
|
|
@@ -6565,28 +6703,26 @@ class Scope {
|
|
|
6565
6703
|
}
|
|
6566
6704
|
|
|
6567
6705
|
/**
|
|
6568
|
-
* @callback contructorCallback
|
|
6569
|
-
* @param {this} self
|
|
6570
|
-
*
|
|
6571
6706
|
* @overload
|
|
6572
6707
|
* @param {String} a1
|
|
6573
6708
|
* @param {ScopeMethod} a2
|
|
6574
6709
|
* @return {this}
|
|
6575
6710
|
*
|
|
6576
6711
|
* @overload
|
|
6577
|
-
* @param {
|
|
6712
|
+
* @param {ScopeConstructorCallback} a1
|
|
6578
6713
|
* @return {this}
|
|
6579
6714
|
*
|
|
6580
|
-
* @param {String|
|
|
6715
|
+
* @param {String|ScopeConstructorCallback} a1
|
|
6581
6716
|
* @param {ScopeMethod} [a2]
|
|
6582
6717
|
*/
|
|
6583
6718
|
add(a1, a2) {
|
|
6719
|
+
this.once = false;
|
|
6584
6720
|
if (isFnc(a1)) {
|
|
6585
|
-
const constructor = /** @type {
|
|
6721
|
+
const constructor = /** @type {ScopeConstructorCallback} */(a1);
|
|
6586
6722
|
this.constructors.push(constructor);
|
|
6587
6723
|
this.execute(() => {
|
|
6588
6724
|
const revertConstructor = constructor(this);
|
|
6589
|
-
if (revertConstructor) {
|
|
6725
|
+
if (isFnc(revertConstructor)) {
|
|
6590
6726
|
this.revertConstructors.push(revertConstructor);
|
|
6591
6727
|
}
|
|
6592
6728
|
});
|
|
@@ -6596,6 +6732,46 @@ class Scope {
|
|
|
6596
6732
|
return this;
|
|
6597
6733
|
}
|
|
6598
6734
|
|
|
6735
|
+
/**
|
|
6736
|
+
* @param {ScopeConstructorCallback} scopeConstructorCallback
|
|
6737
|
+
* @return {this}
|
|
6738
|
+
*/
|
|
6739
|
+
addOnce(scopeConstructorCallback) {
|
|
6740
|
+
this.once = true;
|
|
6741
|
+
if (isFnc(scopeConstructorCallback)) {
|
|
6742
|
+
const currentIndex = this.onceIndex++;
|
|
6743
|
+
const tracked = this.constructorsOnce[currentIndex];
|
|
6744
|
+
if (tracked) return this;
|
|
6745
|
+
const constructor = /** @type {ScopeConstructorCallback} */(scopeConstructorCallback);
|
|
6746
|
+
this.constructorsOnce[currentIndex] = constructor;
|
|
6747
|
+
this.execute(() => {
|
|
6748
|
+
const revertConstructor = constructor(this);
|
|
6749
|
+
if (isFnc(revertConstructor)) {
|
|
6750
|
+
this.revertConstructorsOnce.push(revertConstructor);
|
|
6751
|
+
}
|
|
6752
|
+
});
|
|
6753
|
+
}
|
|
6754
|
+
return this;
|
|
6755
|
+
}
|
|
6756
|
+
|
|
6757
|
+
/**
|
|
6758
|
+
* @param {(scope: this) => Tickable} cb
|
|
6759
|
+
* @return {Tickable}
|
|
6760
|
+
*/
|
|
6761
|
+
keepTime(cb) {
|
|
6762
|
+
this.once = true;
|
|
6763
|
+
const currentIndex = this.onceIndex++;
|
|
6764
|
+
const tracked = /** @type {(scope: this) => Tickable} */(this.constructorsOnce[currentIndex]);
|
|
6765
|
+
if (isFnc(tracked)) return tracked(this);
|
|
6766
|
+
const constructor = /** @type {(scope: this) => Tickable} */(createRefreshable(cb));
|
|
6767
|
+
this.constructorsOnce[currentIndex] = constructor;
|
|
6768
|
+
let trackedTickable;
|
|
6769
|
+
this.execute(() => {
|
|
6770
|
+
trackedTickable = constructor(this);
|
|
6771
|
+
});
|
|
6772
|
+
return trackedTickable;
|
|
6773
|
+
}
|
|
6774
|
+
|
|
6599
6775
|
/**
|
|
6600
6776
|
* @param {Event} e
|
|
6601
6777
|
*/
|
|
@@ -6610,15 +6786,25 @@ class Scope {
|
|
|
6610
6786
|
revert() {
|
|
6611
6787
|
const revertibles = this.revertibles;
|
|
6612
6788
|
const revertConstructors = this.revertConstructors;
|
|
6789
|
+
const revertiblesOnce = this.revertiblesOnce;
|
|
6790
|
+
const revertConstructorsOnce = this.revertConstructorsOnce;
|
|
6613
6791
|
const mqs = this.mediaQueryLists;
|
|
6614
6792
|
let i = revertibles.length;
|
|
6615
|
-
let
|
|
6793
|
+
let j = revertConstructors.length;
|
|
6794
|
+
let k = revertiblesOnce.length;
|
|
6795
|
+
let l = revertConstructorsOnce.length;
|
|
6616
6796
|
while (i--) revertibles[i].revert();
|
|
6617
|
-
while (
|
|
6797
|
+
while (j--) revertConstructors[j](this);
|
|
6798
|
+
while (k--) revertiblesOnce[k].revert();
|
|
6799
|
+
while (l--) revertConstructorsOnce[l](this);
|
|
6618
6800
|
for (let mq in mqs) mqs[mq].removeEventListener('change', this);
|
|
6619
6801
|
revertibles.length = 0;
|
|
6620
6802
|
revertConstructors.length = 0;
|
|
6621
6803
|
this.constructors.length = 0;
|
|
6804
|
+
revertiblesOnce.length = 0;
|
|
6805
|
+
revertConstructorsOnce.length = 0;
|
|
6806
|
+
this.constructorsOnce.length = 0;
|
|
6807
|
+
this.onceIndex = 0;
|
|
6622
6808
|
this.matches = {};
|
|
6623
6809
|
this.methods = {};
|
|
6624
6810
|
this.mediaQueryLists = {};
|
|
@@ -6944,7 +7130,7 @@ const getAnimationDomTarget = linked => {
|
|
|
6944
7130
|
|
|
6945
7131
|
let scrollerIndex = 0;
|
|
6946
7132
|
|
|
6947
|
-
const debugColors = ['#FF4B4B','#FF971B','#FFC730','#F9F640','#7AFF5A','#18FF74','#17E09B','#3CFFEC','#05DBE9','#33B3F1','#638CF9','#C563FE','#FF4FCF','#F93F8A'];
|
|
7133
|
+
const debugColors$1 = ['#FF4B4B','#FF971B','#FFC730','#F9F640','#7AFF5A','#18FF74','#17E09B','#3CFFEC','#05DBE9','#33B3F1','#638CF9','#C563FE','#FF4FCF','#F93F8A'];
|
|
6948
7134
|
|
|
6949
7135
|
/**
|
|
6950
7136
|
* @typedef {Object} ScrollThresholdParam
|
|
@@ -6990,7 +7176,7 @@ class ScrollObserver {
|
|
|
6990
7176
|
* @param {ScrollObserverParams} parameters
|
|
6991
7177
|
*/
|
|
6992
7178
|
constructor(parameters = {}) {
|
|
6993
|
-
if (
|
|
7179
|
+
if (scope.current) scope.current.register(this);
|
|
6994
7180
|
const syncMode = setValue(parameters.sync, 'play pause');
|
|
6995
7181
|
const ease = syncMode ? parseEasings(/** @type {EasingParam} */(syncMode)) : null;
|
|
6996
7182
|
const isLinear = syncMode && (syncMode === 'linear' || syncMode === none);
|
|
@@ -7187,7 +7373,7 @@ class ScrollObserver {
|
|
|
7187
7373
|
const $debug = doc.createElement('div');
|
|
7188
7374
|
const $thresholds = doc.createElement('div');
|
|
7189
7375
|
const $triggers = doc.createElement('div');
|
|
7190
|
-
const color = debugColors[this.index % debugColors.length];
|
|
7376
|
+
const color = debugColors$1[this.index % debugColors$1.length];
|
|
7191
7377
|
const useWin = container.useWin;
|
|
7192
7378
|
const containerWidth = useWin ? container.winWidth : container.width;
|
|
7193
7379
|
const containerHeight = useWin ? container.winHeight : container.height;
|
|
@@ -7545,29 +7731,462 @@ const onScroll = (parameters = {}) => new ScrollObserver(parameters);
|
|
|
7545
7731
|
|
|
7546
7732
|
|
|
7547
7733
|
|
|
7734
|
+
const segmenter = !isUnd(Intl) && Intl.Segmenter;
|
|
7735
|
+
const valueRgx = /\{value\}/g;
|
|
7736
|
+
const indexRgx = /\{i\}/g;
|
|
7737
|
+
const whiteSpaceGroupRgx = /(\s+)/;
|
|
7738
|
+
const whiteSpaceRgx = /^\s+$/;
|
|
7739
|
+
const lineType = 'line';
|
|
7740
|
+
const wordType = 'word';
|
|
7741
|
+
const charType = 'char';
|
|
7742
|
+
const dataLine = `data-line`;
|
|
7743
|
+
|
|
7548
7744
|
/**
|
|
7549
|
-
* @typedef
|
|
7550
|
-
* @property {
|
|
7551
|
-
* @property {
|
|
7552
|
-
* @property {Boolean} [reversed]
|
|
7553
|
-
* @property {Array.<Number>} [grid]
|
|
7554
|
-
* @property {('x'|'y')} [axis]
|
|
7555
|
-
* @property {EasingParam} [ease]
|
|
7556
|
-
* @property {TweenModifier} [modifier]
|
|
7745
|
+
* @typedef {Object} Segment
|
|
7746
|
+
* @property {String} segment
|
|
7747
|
+
* @property {Boolean} [isWordLike]
|
|
7557
7748
|
*/
|
|
7558
7749
|
|
|
7559
7750
|
/**
|
|
7560
|
-
* @
|
|
7561
|
-
* @
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
7565
|
-
|
|
7751
|
+
* @typedef {Object} Segmenter
|
|
7752
|
+
* @property {function(String): Iterable<Segment>} segment
|
|
7753
|
+
*/
|
|
7754
|
+
|
|
7755
|
+
/** @type {Segmenter} */
|
|
7756
|
+
let wordSegmenter = null;
|
|
7757
|
+
/** @type {Segmenter} */
|
|
7758
|
+
let graphemeSegmenter = null;
|
|
7759
|
+
let $splitTemplate = null;
|
|
7760
|
+
|
|
7761
|
+
/**
|
|
7762
|
+
* @param {Segment} seg
|
|
7763
|
+
* @return {Boolean}
|
|
7764
|
+
*/
|
|
7765
|
+
const isSegmentWordLike = seg => {
|
|
7766
|
+
return seg.isWordLike ||
|
|
7767
|
+
seg.segment === ' ' || // Consider spaces as words first, then handle them diffrently later
|
|
7768
|
+
isNum(+seg.segment); // Safari doesn't considers numbers as words
|
|
7769
|
+
};
|
|
7770
|
+
|
|
7771
|
+
/**
|
|
7772
|
+
* @param {HTMLElement} $el
|
|
7773
|
+
*/
|
|
7774
|
+
const setAriaHidden = $el => $el.setAttribute('aria-hidden', 'true');
|
|
7775
|
+
|
|
7776
|
+
/**
|
|
7777
|
+
* @param {DOMTarget} $el
|
|
7778
|
+
* @param {String} type
|
|
7779
|
+
* @return {Array<HTMLElement>}
|
|
7780
|
+
*/
|
|
7781
|
+
const getAllTopLevelElements = ($el, type) => [.../** @type {*} */($el.querySelectorAll(`[data-${type}]:not([data-${type}] [data-${type}])`))];
|
|
7782
|
+
|
|
7783
|
+
const debugColors = { line: '#00D672', word: '#FF4B4B', char: '#5A87FF' };
|
|
7784
|
+
|
|
7785
|
+
/**
|
|
7786
|
+
* @param {HTMLElement} $el
|
|
7787
|
+
*/
|
|
7788
|
+
const filterEmptyElements = $el => {
|
|
7789
|
+
if (!$el.childElementCount && !$el.textContent.trim()) {
|
|
7790
|
+
const $parent = $el.parentElement;
|
|
7791
|
+
$el.remove();
|
|
7792
|
+
if ($parent) filterEmptyElements($parent);
|
|
7793
|
+
}
|
|
7794
|
+
};
|
|
7795
|
+
|
|
7796
|
+
/**
|
|
7797
|
+
* @param {HTMLElement} $el
|
|
7798
|
+
* @param {Number} lineIndex
|
|
7799
|
+
* @param {Set<HTMLElement>} bin
|
|
7800
|
+
* @returns {Set<HTMLElement>}
|
|
7801
|
+
*/
|
|
7802
|
+
const filterLineElements = ($el, lineIndex, bin) => {
|
|
7803
|
+
const dataLineAttr = $el.getAttribute(dataLine);
|
|
7804
|
+
if (dataLineAttr !== null && +dataLineAttr !== lineIndex || $el.tagName === 'BR') bin.add($el);
|
|
7805
|
+
let i = $el.childElementCount;
|
|
7806
|
+
while (i--) filterLineElements(/** @type {HTMLElement} */($el.children[i]), lineIndex, bin);
|
|
7807
|
+
return bin;
|
|
7808
|
+
};
|
|
7809
|
+
|
|
7810
|
+
/**
|
|
7811
|
+
* @param {'line'|'word'|'char'} type
|
|
7812
|
+
* @param {splitTemplateParams} params
|
|
7813
|
+
* @return {String}
|
|
7814
|
+
*/
|
|
7815
|
+
const generateTemplate = (type, params = {}) => {
|
|
7816
|
+
let template = ``;
|
|
7817
|
+
const classString = isStr(params.class) ? ` class="${params.class}"` : '';
|
|
7818
|
+
const cloneType = setValue(params.clone, false);
|
|
7819
|
+
const wrapType = setValue(params.wrap, false);
|
|
7820
|
+
const overflow = wrapType ? wrapType === true ? 'clip' : wrapType : cloneType ? 'clip' : false;
|
|
7821
|
+
if (wrapType) template += `<span${overflow ? ` style="overflow:${overflow};"` : ''}>`;
|
|
7822
|
+
template += `<span${classString}${cloneType ? ` style="position:relative;"` : ''} data-${type}="{i}">`;
|
|
7823
|
+
if (cloneType) {
|
|
7824
|
+
const left = cloneType === 'left' ? '-100%' : cloneType === 'right' ? '100%' : '0';
|
|
7825
|
+
const top = cloneType === 'top' ? '-100%' : cloneType === 'bottom' ? '100%' : '0';
|
|
7826
|
+
template += `<span>{value}</span>`;
|
|
7827
|
+
template += `<span inert style="position:absolute;top:${top};left:${left};white-space:nowrap;">{value}</span>`;
|
|
7828
|
+
} else {
|
|
7829
|
+
template += `{value}`;
|
|
7830
|
+
}
|
|
7831
|
+
template += `</span>`;
|
|
7832
|
+
if (wrapType) template += `</span>`;
|
|
7833
|
+
return template;
|
|
7834
|
+
};
|
|
7835
|
+
|
|
7836
|
+
/**
|
|
7837
|
+
* @param {String|SplitFunctionValue} htmlTemplate
|
|
7838
|
+
* @param {Array<HTMLElement>} store
|
|
7839
|
+
* @param {Node|HTMLElement} node
|
|
7840
|
+
* @param {DocumentFragment} $parentFragment
|
|
7841
|
+
* @param {'line'|'word'|'char'} type
|
|
7842
|
+
* @param {Boolean} debug
|
|
7843
|
+
* @param {Number} lineIndex
|
|
7844
|
+
* @param {Number} [wordIndex]
|
|
7845
|
+
* @param {Number} [charIndex]
|
|
7846
|
+
* @return {HTMLElement}
|
|
7847
|
+
*/
|
|
7848
|
+
const processHTMLTemplate = (htmlTemplate, store, node, $parentFragment, type, debug, lineIndex, wordIndex, charIndex) => {
|
|
7849
|
+
const isLine = type === lineType;
|
|
7850
|
+
const isChar = type === charType;
|
|
7851
|
+
const className = `_${type}_`;
|
|
7852
|
+
const template = isFnc(htmlTemplate) ? htmlTemplate(node) : htmlTemplate;
|
|
7853
|
+
const displayStyle = isLine ? 'block' : 'inline-block';
|
|
7854
|
+
$splitTemplate.innerHTML = template
|
|
7855
|
+
.replace(valueRgx, `<i class="${className}"></i>`)
|
|
7856
|
+
.replace(indexRgx, `${isChar ? charIndex : isLine ? lineIndex : wordIndex}`);
|
|
7857
|
+
const $content = $splitTemplate.content;
|
|
7858
|
+
const $highestParent = /** @type {HTMLElement} */($content.firstElementChild);
|
|
7859
|
+
const $split = /** @type {HTMLElement} */($content.querySelector(`[data-${type}]`)) || $highestParent;
|
|
7860
|
+
const $replacables = /** @type {NodeListOf<HTMLElement>} */($content.querySelectorAll(`i.${className}`));
|
|
7861
|
+
const replacablesLength = $replacables.length;
|
|
7862
|
+
if (replacablesLength) {
|
|
7863
|
+
$highestParent.style.display = displayStyle;
|
|
7864
|
+
$split.style.display = displayStyle;
|
|
7865
|
+
$split.setAttribute(dataLine, `${lineIndex}`);
|
|
7866
|
+
if (!isLine) {
|
|
7867
|
+
$split.setAttribute('data-word', `${wordIndex}`);
|
|
7868
|
+
if (isChar) $split.setAttribute('data-char', `${charIndex}`);
|
|
7869
|
+
}
|
|
7870
|
+
let i = replacablesLength;
|
|
7871
|
+
while (i--) {
|
|
7872
|
+
const $replace = $replacables[i];
|
|
7873
|
+
const $closestParent = $replace.parentElement;
|
|
7874
|
+
$closestParent.style.display = displayStyle;
|
|
7875
|
+
if (isLine) {
|
|
7876
|
+
$closestParent.innerHTML = /** @type {HTMLElement} */(node).innerHTML;
|
|
7877
|
+
} else {
|
|
7878
|
+
$closestParent.replaceChild(node.cloneNode(true), $replace);
|
|
7879
|
+
}
|
|
7880
|
+
}
|
|
7881
|
+
store.push($split);
|
|
7882
|
+
$parentFragment.appendChild($content);
|
|
7883
|
+
} else {
|
|
7884
|
+
console.warn(`The expression "{value}" is missing from the provided template.`);
|
|
7885
|
+
}
|
|
7886
|
+
if (debug) $highestParent.style.outline = `1px dotted ${debugColors[type]}`;
|
|
7887
|
+
return $highestParent;
|
|
7888
|
+
};
|
|
7889
|
+
|
|
7890
|
+
/**
|
|
7891
|
+
* A class that splits text into words and wraps them in span elements while preserving the original HTML structure.
|
|
7892
|
+
* @class
|
|
7893
|
+
*/
|
|
7894
|
+
class TextSplitter {
|
|
7895
|
+
/**
|
|
7896
|
+
* @param {HTMLElement|NodeList|String|Array<HTMLElement>} target
|
|
7897
|
+
* @param {TextSplitterParams} [parameters]
|
|
7898
|
+
*/
|
|
7899
|
+
constructor(target, parameters = {}) {
|
|
7900
|
+
// Only init segmenters when needed
|
|
7901
|
+
if (!wordSegmenter) wordSegmenter = segmenter ? new segmenter([], { granularity: wordType }) : {
|
|
7902
|
+
segment: (text) => {
|
|
7903
|
+
const segments = [];
|
|
7904
|
+
const words = text.split(whiteSpaceGroupRgx);
|
|
7905
|
+
for (let i = 0, l = words.length; i < l; i++) {
|
|
7906
|
+
const segment = words[i];
|
|
7907
|
+
segments.push({
|
|
7908
|
+
segment,
|
|
7909
|
+
isWordLike: !whiteSpaceRgx.test(segment), // Consider non-whitespace as word-like
|
|
7910
|
+
});
|
|
7911
|
+
}
|
|
7912
|
+
return segments;
|
|
7913
|
+
}
|
|
7914
|
+
};
|
|
7915
|
+
if (!graphemeSegmenter) graphemeSegmenter = segmenter ? new segmenter([], { granularity: 'grapheme' }) : {
|
|
7916
|
+
segment: text => [...text].map(char => ({ segment: char }))
|
|
7917
|
+
};
|
|
7918
|
+
if (!$splitTemplate && isBrowser) $splitTemplate = doc.createElement('template');
|
|
7919
|
+
if (scope.current) scope.current.register(this);
|
|
7920
|
+
const { words, chars, lines, accessible, includeSpaces, debug } = parameters;
|
|
7921
|
+
const $target = /** @type {HTMLElement} */((target = isArr(target) ? target[0] : target) && /** @type {Node} */(target).nodeType ? target : (getNodeList(target) || [])[0]);
|
|
7922
|
+
const lineParams = lines === true ? {} : lines;
|
|
7923
|
+
const wordParams = words === true || isUnd(words) ? {} : words;
|
|
7924
|
+
const charParams = chars === true ? {} : chars;
|
|
7925
|
+
this.debug = setValue(debug, false);
|
|
7926
|
+
this.includeSpaces = setValue(includeSpaces, false);
|
|
7927
|
+
this.accessible = setValue(accessible, true);
|
|
7928
|
+
this.linesOnly = lineParams && (!wordParams && !charParams);
|
|
7929
|
+
/** @type {String|false|SplitFunctionValue} */
|
|
7930
|
+
this.lineTemplate = isObj(lineParams) ? generateTemplate(lineType, /** @type {splitTemplateParams} */(lineParams)) : lineParams;
|
|
7931
|
+
/** @type {String|false|SplitFunctionValue} */
|
|
7932
|
+
this.wordTemplate = isObj(wordParams) || this.linesOnly ? generateTemplate(wordType, /** @type {splitTemplateParams} */(wordParams)) : wordParams;
|
|
7933
|
+
/** @type {String|false|SplitFunctionValue} */
|
|
7934
|
+
this.charTemplate = isObj(charParams) ? generateTemplate(charType, /** @type {splitTemplateParams} */(charParams)) : charParams;
|
|
7935
|
+
this.$target = $target;
|
|
7936
|
+
this.html = $target && $target.innerHTML;
|
|
7937
|
+
this.lines = [];
|
|
7938
|
+
this.words = [];
|
|
7939
|
+
this.chars = [];
|
|
7940
|
+
this.effects = [];
|
|
7941
|
+
this.effectsCleanups = [];
|
|
7942
|
+
this.cache = null;
|
|
7943
|
+
this.ready = false;
|
|
7944
|
+
this.width = 0;
|
|
7945
|
+
this.resizeTimeout = null;
|
|
7946
|
+
const handleSplit = () => this.html && (lineParams || wordParams || charParams) && this.split();
|
|
7947
|
+
// Make sure this is declared before calling handleSplit() in case revert() is called inside an effect callback
|
|
7948
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
7949
|
+
// Use a setTimeout instead of a Timer for better tree shaking
|
|
7950
|
+
clearTimeout(this.resizeTimeout);
|
|
7951
|
+
this.resizeTimeout = setTimeout(() => {
|
|
7952
|
+
const currentWidth = /** @type {HTMLElement} */($target).offsetWidth;
|
|
7953
|
+
if (currentWidth === this.width) return;
|
|
7954
|
+
this.width = currentWidth;
|
|
7955
|
+
handleSplit();
|
|
7956
|
+
}, 150);
|
|
7957
|
+
});
|
|
7958
|
+
// Only declare the font ready promise when splitting by lines and not alreay split
|
|
7959
|
+
if (this.lineTemplate && !this.ready) {
|
|
7960
|
+
doc.fonts.ready.then(handleSplit);
|
|
7961
|
+
} else {
|
|
7962
|
+
handleSplit();
|
|
7963
|
+
}
|
|
7964
|
+
$target ? this.resizeObserver.observe($target) : console.warn('No Text Splitter target found.');
|
|
7965
|
+
}
|
|
7966
|
+
|
|
7967
|
+
/**
|
|
7968
|
+
* @param {(...args: any[]) => Tickable | (() => void)} effect
|
|
7969
|
+
* @return this
|
|
7970
|
+
*/
|
|
7971
|
+
addEffect(effect) {
|
|
7972
|
+
if (!isFnc(effect)) return console.warn('Effect must return a function.');
|
|
7973
|
+
const refreshableEffect = createRefreshable(effect);
|
|
7974
|
+
this.effects.push(refreshableEffect);
|
|
7975
|
+
if (this.ready) this.effectsCleanups[this.effects.length - 1] = refreshableEffect(this);
|
|
7976
|
+
return this;
|
|
7977
|
+
}
|
|
7978
|
+
|
|
7979
|
+
revert() {
|
|
7980
|
+
clearTimeout(this.resizeTimeout);
|
|
7981
|
+
this.lines.length = this.words.length = this.chars.length = 0;
|
|
7982
|
+
this.resizeObserver.disconnect();
|
|
7983
|
+
// Make sure to revert the effects after disconnecting the resizeObserver to avoid triggering it in the process
|
|
7984
|
+
this.effectsCleanups.forEach(cleanup => isFnc(cleanup) ? cleanup(this) : cleanup.revert && cleanup.revert());
|
|
7985
|
+
this.$target.innerHTML = this.html;
|
|
7986
|
+
return this;
|
|
7987
|
+
}
|
|
7988
|
+
|
|
7989
|
+
/**
|
|
7990
|
+
* Recursively processes a node and its children
|
|
7991
|
+
* @param {Node} node
|
|
7992
|
+
*/
|
|
7993
|
+
splitNode(node) {
|
|
7994
|
+
const wordTemplate = this.wordTemplate;
|
|
7995
|
+
const charTemplate = this.charTemplate;
|
|
7996
|
+
const includeSpaces = this.includeSpaces;
|
|
7997
|
+
const debug = this.debug;
|
|
7998
|
+
const nodeType = node.nodeType;
|
|
7999
|
+
if (nodeType === 3) {
|
|
8000
|
+
const nodeText = node.nodeValue;
|
|
8001
|
+
// If the nodeText is only whitespace, leave it as is
|
|
8002
|
+
if (nodeText.trim()) {
|
|
8003
|
+
const tempWords = [];
|
|
8004
|
+
const words = this.words;
|
|
8005
|
+
const chars = this.chars;
|
|
8006
|
+
const wordSegments = wordSegmenter.segment(nodeText);
|
|
8007
|
+
const $wordsFragment = doc.createDocumentFragment();
|
|
8008
|
+
let prevSeg = null;
|
|
8009
|
+
for (const wordSegment of wordSegments) {
|
|
8010
|
+
const segment = wordSegment.segment;
|
|
8011
|
+
const isWordLike = isSegmentWordLike(wordSegment);
|
|
8012
|
+
// Determine if this segment should be a new word, first segment always becomes a new word
|
|
8013
|
+
if (!prevSeg || (isWordLike && (prevSeg && (isSegmentWordLike(prevSeg))))) {
|
|
8014
|
+
tempWords.push(segment);
|
|
8015
|
+
} else {
|
|
8016
|
+
// Only concatenate if both current and previous are non-word-like and don't contain spaces
|
|
8017
|
+
const lastWordIndex = tempWords.length - 1;
|
|
8018
|
+
const lastWord = tempWords[lastWordIndex];
|
|
8019
|
+
if (!lastWord.includes(' ') && !segment.includes(' ')) {
|
|
8020
|
+
tempWords[lastWordIndex] += segment;
|
|
8021
|
+
} else {
|
|
8022
|
+
tempWords.push(segment);
|
|
8023
|
+
}
|
|
8024
|
+
}
|
|
8025
|
+
prevSeg = wordSegment;
|
|
8026
|
+
}
|
|
8027
|
+
|
|
8028
|
+
for (let i = 0, l = tempWords.length; i < l; i++) {
|
|
8029
|
+
const word = tempWords[i];
|
|
8030
|
+
if (!word.trim()) {
|
|
8031
|
+
// Preserve whitespace only if includeSpaces is false and if the current space is not the first node
|
|
8032
|
+
if (i && includeSpaces) continue;
|
|
8033
|
+
$wordsFragment.appendChild(doc.createTextNode(word));
|
|
8034
|
+
} else {
|
|
8035
|
+
const nextWord = tempWords[i + 1];
|
|
8036
|
+
const hasWordFollowingSpace = includeSpaces && nextWord && !nextWord.trim();
|
|
8037
|
+
const wordToProcess = word;
|
|
8038
|
+
const charSegments = charTemplate ? graphemeSegmenter.segment(wordToProcess) : null;
|
|
8039
|
+
const $charsFragment = charTemplate ? doc.createDocumentFragment() : doc.createTextNode(hasWordFollowingSpace ? word + '\xa0' : word);
|
|
8040
|
+
if (charTemplate) {
|
|
8041
|
+
const charSegmentsArray = [...charSegments];
|
|
8042
|
+
for (let j = 0, jl = charSegmentsArray.length; j < jl; j++) {
|
|
8043
|
+
const charSegment = charSegmentsArray[j];
|
|
8044
|
+
const isLastChar = j === jl - 1;
|
|
8045
|
+
// If this is the last character and includeSpaces is true with a following space, append the space
|
|
8046
|
+
const charText = isLastChar && hasWordFollowingSpace ? charSegment.segment + '\xa0' : charSegment.segment;
|
|
8047
|
+
const $charNode = doc.createTextNode(charText);
|
|
8048
|
+
processHTMLTemplate(charTemplate, chars, $charNode, /** @type {DocumentFragment} */($charsFragment), charType, debug, -1, words.length, chars.length);
|
|
8049
|
+
}
|
|
8050
|
+
}
|
|
8051
|
+
if (wordTemplate) {
|
|
8052
|
+
processHTMLTemplate(wordTemplate, words, $charsFragment, $wordsFragment, wordType, debug, -1, words.length, chars.length);
|
|
8053
|
+
// Chars elements must be re-parsed in the split() method if both words and chars are parsed
|
|
8054
|
+
} else if (charTemplate) {
|
|
8055
|
+
$wordsFragment.appendChild($charsFragment);
|
|
8056
|
+
} else {
|
|
8057
|
+
$wordsFragment.appendChild(doc.createTextNode(word));
|
|
8058
|
+
}
|
|
8059
|
+
// Skip the next iteration if we included a space
|
|
8060
|
+
if (hasWordFollowingSpace) i++;
|
|
8061
|
+
}
|
|
8062
|
+
}
|
|
8063
|
+
node.parentNode.replaceChild($wordsFragment, node);
|
|
8064
|
+
}
|
|
8065
|
+
} else if (nodeType === 1) {
|
|
8066
|
+
// Converting to an array is necessary to work around childNodes pottential mutation
|
|
8067
|
+
const childNodes = /** @type {Array<Node>} */([.../** @type {*} */(node.childNodes)]);
|
|
8068
|
+
for (let i = 0, l = childNodes.length; i < l; i++) this.splitNode(childNodes[i]);
|
|
8069
|
+
}
|
|
8070
|
+
}
|
|
8071
|
+
|
|
8072
|
+
/**
|
|
8073
|
+
* @param {Boolean} clearCache
|
|
8074
|
+
* @return {this}
|
|
8075
|
+
*/
|
|
8076
|
+
split(clearCache = false) {
|
|
8077
|
+
const $el = this.$target;
|
|
8078
|
+
const isCached = !!this.cache && !clearCache;
|
|
8079
|
+
const lineTemplate = this.lineTemplate;
|
|
8080
|
+
const wordTemplate = this.wordTemplate;
|
|
8081
|
+
const charTemplate = this.charTemplate;
|
|
8082
|
+
const fontsReady = doc.fonts.status !== 'loading';
|
|
8083
|
+
const canSplitLines = lineTemplate && fontsReady;
|
|
8084
|
+
this.ready = !lineTemplate || fontsReady;
|
|
8085
|
+
if (!isCached) {
|
|
8086
|
+
if (clearCache) {
|
|
8087
|
+
$el.innerHTML = this.html;
|
|
8088
|
+
this.words.length = this.chars.length = 0;
|
|
8089
|
+
}
|
|
8090
|
+
this.splitNode($el);
|
|
8091
|
+
this.cache = $el.innerHTML;
|
|
8092
|
+
}
|
|
8093
|
+
// Always reset the html when splitting by lines
|
|
8094
|
+
if (canSplitLines) {
|
|
8095
|
+
// No need to revert effects animations here since it's already taken care by the refreshable
|
|
8096
|
+
this.effectsCleanups.forEach(cleanup => isFnc(cleanup) && cleanup(this));
|
|
8097
|
+
if (isCached) $el.innerHTML = this.cache;
|
|
8098
|
+
this.lines.length = 0;
|
|
8099
|
+
if (wordTemplate) this.words = getAllTopLevelElements($el, wordType);
|
|
8100
|
+
}
|
|
8101
|
+
// Always reparse characters after a line reset or if both words and chars are activated
|
|
8102
|
+
if (charTemplate && (canSplitLines || wordTemplate)) {
|
|
8103
|
+
this.chars = getAllTopLevelElements($el, charType);
|
|
8104
|
+
}
|
|
8105
|
+
// Words are used when lines only and prioritized over chars
|
|
8106
|
+
const elementsArray = this.words.length ? this.words : this.chars;
|
|
8107
|
+
let y, linesCount = 0;
|
|
8108
|
+
for (let i = 0, l = elementsArray.length; i < l; i++) {
|
|
8109
|
+
const $el = elementsArray[i];
|
|
8110
|
+
const { top, height } = $el.getBoundingClientRect();
|
|
8111
|
+
if (y && top - y > height * .5) linesCount++;
|
|
8112
|
+
$el.setAttribute(dataLine, `${linesCount}`);
|
|
8113
|
+
const nested = $el.querySelectorAll(`[${dataLine}]`);
|
|
8114
|
+
let c = nested.length;
|
|
8115
|
+
while (c--) nested[c].setAttribute(dataLine, `${linesCount}`);
|
|
8116
|
+
y = top;
|
|
8117
|
+
}
|
|
8118
|
+
if (canSplitLines) {
|
|
8119
|
+
const linesFragment = doc.createDocumentFragment();
|
|
8120
|
+
const parents = new Set();
|
|
8121
|
+
const clones = [];
|
|
8122
|
+
for (let lineIndex = 0; lineIndex < linesCount + 1; lineIndex++) {
|
|
8123
|
+
const $clone = /** @type {HTMLElement} */($el.cloneNode(true));
|
|
8124
|
+
filterLineElements($clone, lineIndex, new Set()).forEach($el => {
|
|
8125
|
+
const $parent = $el.parentElement;
|
|
8126
|
+
if ($parent) parents.add($parent);
|
|
8127
|
+
$el.remove();
|
|
8128
|
+
});
|
|
8129
|
+
clones.push($clone);
|
|
8130
|
+
}
|
|
8131
|
+
parents.forEach(filterEmptyElements);
|
|
8132
|
+
for (let cloneIndex = 0, clonesLength = clones.length; cloneIndex < clonesLength; cloneIndex++) {
|
|
8133
|
+
processHTMLTemplate(lineTemplate, this.lines, clones[cloneIndex], linesFragment, lineType, this.debug, cloneIndex);
|
|
8134
|
+
}
|
|
8135
|
+
$el.innerHTML = '';
|
|
8136
|
+
$el.appendChild(linesFragment);
|
|
8137
|
+
if (wordTemplate) this.words = getAllTopLevelElements($el, wordType);
|
|
8138
|
+
if (charTemplate) this.chars = getAllTopLevelElements($el, charType);
|
|
8139
|
+
}
|
|
8140
|
+
// Remove the word wrappers and clear the words array if lines split only
|
|
8141
|
+
if (this.linesOnly) {
|
|
8142
|
+
const words = this.words;
|
|
8143
|
+
let w = words.length;
|
|
8144
|
+
while (w--) {
|
|
8145
|
+
const $word = words[w];
|
|
8146
|
+
$word.replaceWith($word.textContent);
|
|
8147
|
+
}
|
|
8148
|
+
words.length = 0;
|
|
8149
|
+
}
|
|
8150
|
+
if (canSplitLines || clearCache) {
|
|
8151
|
+
this.effects.forEach((effect, i) => this.effectsCleanups[i] = effect(this));
|
|
8152
|
+
}
|
|
8153
|
+
if (this.accessible && (canSplitLines || !isCached)) {
|
|
8154
|
+
const $accessible = doc.createElement('span');
|
|
8155
|
+
// Make the accessible element visually-hidden (https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html)
|
|
8156
|
+
$accessible.style.cssText = `position:absolute;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);width:1px;height:1px;white-space:nowrap;`;
|
|
8157
|
+
// $accessible.setAttribute('tabindex', '-1');
|
|
8158
|
+
$accessible.innerHTML = this.html;
|
|
8159
|
+
$el.insertBefore($accessible, $el.firstChild);
|
|
8160
|
+
this.lines.forEach(setAriaHidden);
|
|
8161
|
+
this.words.forEach(setAriaHidden);
|
|
8162
|
+
this.chars.forEach(setAriaHidden);
|
|
8163
|
+
}
|
|
8164
|
+
this.width = /** @type {HTMLElement} */($el).offsetWidth;
|
|
8165
|
+
return this;
|
|
8166
|
+
}
|
|
8167
|
+
|
|
8168
|
+
refresh() {
|
|
8169
|
+
this.split(true);
|
|
8170
|
+
}
|
|
8171
|
+
}
|
|
8172
|
+
|
|
8173
|
+
/**
|
|
8174
|
+
* @param {HTMLElement|NodeList|String|Array<HTMLElement>} target
|
|
8175
|
+
* @param {TextSplitterParams} [parameters]
|
|
8176
|
+
* @return {TextSplitter}
|
|
7566
8177
|
*/
|
|
8178
|
+
const split = (target, parameters) => new TextSplitter(target, parameters);
|
|
8179
|
+
|
|
8180
|
+
const text = {
|
|
8181
|
+
split,
|
|
8182
|
+
};
|
|
8183
|
+
|
|
8184
|
+
|
|
8185
|
+
|
|
7567
8186
|
|
|
7568
8187
|
/**
|
|
7569
8188
|
* @param {Number|String|[Number|String,Number|String]} val
|
|
7570
|
-
* @param {
|
|
8189
|
+
* @param {StaggerParams} params
|
|
7571
8190
|
* @return {StaggerFunction}
|
|
7572
8191
|
*/
|
|
7573
8192
|
const stagger = (val, params = {}) => {
|
|
@@ -7581,20 +8200,27 @@ const stagger = (val, params = {}) => {
|
|
|
7581
8200
|
const staggerEase = hasSpring ? /** @type {Spring} */(ease).ease : hasEasing ? parseEasings(ease) : null;
|
|
7582
8201
|
const grid = params.grid;
|
|
7583
8202
|
const axis = params.axis;
|
|
8203
|
+
const customTotal = params.total;
|
|
7584
8204
|
const fromFirst = isUnd(from) || from === 0 || from === 'first';
|
|
7585
8205
|
const fromCenter = from === 'center';
|
|
7586
8206
|
const fromLast = from === 'last';
|
|
8207
|
+
const fromRandom = from === 'random';
|
|
7587
8208
|
const isRange = isArr(val);
|
|
8209
|
+
const useProp = params.use;
|
|
7588
8210
|
const val1 = isRange ? parseNumber(val[0]) : parseNumber(val);
|
|
7589
8211
|
const val2 = isRange ? parseNumber(val[1]) : 0;
|
|
7590
8212
|
const unitMatch = unitsExecRgx.exec((isRange ? val[1] : val) + emptyString);
|
|
7591
8213
|
const start = params.start || 0 + (isRange ? val1 : 0);
|
|
7592
8214
|
let fromIndex = fromFirst ? 0 : isNum(from) ? from : 0;
|
|
7593
|
-
return (
|
|
7594
|
-
|
|
7595
|
-
|
|
8215
|
+
return (target, i, t, tl) => {
|
|
8216
|
+
const [ registeredTarget ] = registerTargets(target);
|
|
8217
|
+
const total = isUnd(customTotal) ? t : customTotal;
|
|
8218
|
+
const customIndex = !isUnd(useProp) ? isFnc(useProp) ? useProp(registeredTarget, i, total) : getOriginalAnimatableValue(registeredTarget, useProp) : false;
|
|
8219
|
+
const staggerIndex = isNum(customIndex) || isStr(customIndex) && isNum(+customIndex) ? +customIndex : i;
|
|
8220
|
+
if (fromCenter) fromIndex = (total - 1) / 2;
|
|
8221
|
+
if (fromLast) fromIndex = total - 1;
|
|
7596
8222
|
if (!values.length) {
|
|
7597
|
-
for (let index = 0; index <
|
|
8223
|
+
for (let index = 0; index < total; index++) {
|
|
7598
8224
|
if (!grid) {
|
|
7599
8225
|
values.push(abs(fromIndex - index));
|
|
7600
8226
|
} else {
|
|
@@ -7613,15 +8239,16 @@ const stagger = (val, params = {}) => {
|
|
|
7613
8239
|
}
|
|
7614
8240
|
if (staggerEase) values = values.map(val => staggerEase(val / maxValue) * maxValue);
|
|
7615
8241
|
if (reversed) values = values.map(val => axis ? (val < 0) ? val * -1 : -val : abs(maxValue - val));
|
|
8242
|
+
if (fromRandom) values = shuffle(values);
|
|
7616
8243
|
}
|
|
7617
8244
|
const spacing = isRange ? (val2 - val1) / maxValue : val1;
|
|
7618
8245
|
const offset = tl ? parseTimelinePosition(tl, isUnd(params.start) ? tl.iterationDuration : start) : /** @type {Number} */(start);
|
|
7619
8246
|
/** @type {String|Number} */
|
|
7620
|
-
let output = offset + ((spacing * round(values[
|
|
8247
|
+
let output = offset + ((spacing * round(values[staggerIndex], 2)) || 0);
|
|
7621
8248
|
if (params.modifier) output = params.modifier(output);
|
|
7622
8249
|
if (unitMatch) output = `${output}${unitMatch[2]}`;
|
|
7623
8250
|
return output;
|
|
7624
8251
|
}
|
|
7625
8252
|
};
|
|
7626
8253
|
|
|
7627
|
-
export { Animatable, Draggable, JSAnimation, Scope, ScrollObserver, Spring, Timeline, Timer, WAAPIAnimation, animate, createAnimatable, createDraggable, createScope, createSpring, createTimeline, createTimer, eases, engine, onScroll, scrollContainers, stagger, svg, utils, waapi };
|
|
8254
|
+
export { Animatable, Draggable, JSAnimation, Scope, ScrollObserver, Spring, TextSplitter, Timeline, Timer, WAAPIAnimation, animate, createAnimatable, createDraggable, createScope, createSpring, createTimeline, createTimer, eases, engine, onScroll, scrollContainers, stagger, svg, text, utils, waapi };
|