animejs 4.3.0-beta.2 → 4.3.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 +16 -17
- package/dist/bundles/anime.esm.js +446 -245
- package/dist/bundles/anime.esm.min.js +3 -3
- package/dist/bundles/anime.umd.js +446 -245
- package/dist/bundles/anime.umd.min.js +3 -3
- package/dist/modules/animatable/animatable.cjs +2 -2
- package/dist/modules/animatable/animatable.js +2 -2
- package/dist/modules/animatable/index.cjs +2 -2
- package/dist/modules/animatable/index.js +2 -2
- package/dist/modules/animation/additive.cjs +2 -2
- package/dist/modules/animation/additive.js +2 -2
- package/dist/modules/animation/animation.cjs +8 -5
- package/dist/modules/animation/animation.js +9 -6
- package/dist/modules/animation/composition.cjs +2 -2
- package/dist/modules/animation/composition.js +2 -2
- package/dist/modules/animation/index.cjs +2 -2
- package/dist/modules/animation/index.js +2 -2
- package/dist/modules/core/clock.cjs +2 -2
- package/dist/modules/core/clock.js +2 -2
- package/dist/modules/core/colors.cjs +2 -2
- package/dist/modules/core/colors.js +2 -2
- package/dist/modules/core/consts.cjs +2 -2
- package/dist/modules/core/consts.js +2 -2
- package/dist/modules/core/globals.cjs +3 -3
- package/dist/modules/core/globals.js +3 -3
- package/dist/modules/core/helpers.cjs +4 -4
- package/dist/modules/core/helpers.js +4 -4
- package/dist/modules/core/render.cjs +2 -2
- package/dist/modules/core/render.js +2 -2
- package/dist/modules/core/styles.cjs +2 -2
- package/dist/modules/core/styles.js +2 -2
- package/dist/modules/core/targets.cjs +2 -2
- package/dist/modules/core/targets.js +2 -2
- package/dist/modules/core/transforms.cjs +2 -2
- package/dist/modules/core/transforms.js +2 -2
- package/dist/modules/core/units.cjs +2 -2
- package/dist/modules/core/units.js +2 -2
- package/dist/modules/core/values.cjs +2 -2
- package/dist/modules/core/values.js +2 -2
- package/dist/modules/draggable/draggable.cjs +2 -2
- package/dist/modules/draggable/draggable.js +2 -2
- package/dist/modules/draggable/index.cjs +2 -2
- package/dist/modules/draggable/index.js +2 -2
- package/dist/modules/easings/cubic-bezier/index.cjs +2 -2
- package/dist/modules/easings/cubic-bezier/index.js +2 -2
- package/dist/modules/easings/eases/index.cjs +2 -2
- package/dist/modules/easings/eases/index.js +2 -2
- package/dist/modules/easings/eases/parser.cjs +2 -2
- package/dist/modules/easings/eases/parser.js +2 -2
- package/dist/modules/easings/index.cjs +2 -2
- package/dist/modules/easings/index.js +2 -2
- package/dist/modules/easings/irregular/index.cjs +2 -2
- package/dist/modules/easings/irregular/index.js +2 -2
- package/dist/modules/easings/linear/index.cjs +2 -2
- package/dist/modules/easings/linear/index.js +2 -2
- package/dist/modules/easings/none.cjs +2 -2
- package/dist/modules/easings/none.js +2 -2
- package/dist/modules/easings/spring/index.cjs +2 -2
- package/dist/modules/easings/spring/index.js +2 -2
- package/dist/modules/easings/steps/index.cjs +2 -2
- package/dist/modules/easings/steps/index.js +2 -2
- package/dist/modules/engine/engine.cjs +2 -2
- package/dist/modules/engine/engine.js +2 -2
- package/dist/modules/engine/index.cjs +2 -2
- package/dist/modules/engine/index.js +2 -2
- package/dist/modules/events/index.cjs +2 -2
- package/dist/modules/events/index.js +2 -2
- package/dist/modules/events/scroll.cjs +2 -2
- package/dist/modules/events/scroll.js +2 -2
- package/dist/modules/index.cjs +2 -2
- package/dist/modules/index.js +2 -2
- package/dist/modules/layout/index.cjs +2 -2
- package/dist/modules/layout/index.js +2 -2
- package/dist/modules/layout/layout.cjs +427 -228
- package/dist/modules/layout/layout.d.ts +44 -38
- package/dist/modules/layout/layout.js +429 -230
- package/dist/modules/scope/index.cjs +2 -2
- package/dist/modules/scope/index.js +2 -2
- package/dist/modules/scope/scope.cjs +2 -2
- package/dist/modules/scope/scope.js +2 -2
- package/dist/modules/svg/drawable.cjs +2 -2
- package/dist/modules/svg/drawable.js +2 -2
- package/dist/modules/svg/helpers.cjs +2 -2
- package/dist/modules/svg/helpers.js +2 -2
- package/dist/modules/svg/index.cjs +2 -2
- package/dist/modules/svg/index.js +2 -2
- package/dist/modules/svg/morphto.cjs +2 -2
- package/dist/modules/svg/morphto.js +2 -2
- package/dist/modules/svg/motionpath.cjs +2 -2
- package/dist/modules/svg/motionpath.js +2 -2
- package/dist/modules/text/index.cjs +2 -2
- package/dist/modules/text/index.js +2 -2
- package/dist/modules/text/split.cjs +2 -2
- package/dist/modules/text/split.js +2 -2
- package/dist/modules/timeline/index.cjs +2 -2
- package/dist/modules/timeline/index.js +2 -2
- package/dist/modules/timeline/position.cjs +2 -2
- package/dist/modules/timeline/position.js +2 -2
- package/dist/modules/timeline/timeline.cjs +2 -2
- package/dist/modules/timeline/timeline.js +2 -2
- package/dist/modules/timer/index.cjs +2 -2
- package/dist/modules/timer/index.js +2 -2
- package/dist/modules/timer/timer.cjs +5 -4
- package/dist/modules/timer/timer.d.ts +2 -1
- package/dist/modules/timer/timer.js +5 -4
- package/dist/modules/types/index.d.ts +6 -6
- package/dist/modules/utils/chainable.cjs +2 -2
- package/dist/modules/utils/chainable.js +2 -2
- package/dist/modules/utils/index.cjs +2 -2
- package/dist/modules/utils/index.js +2 -2
- package/dist/modules/utils/number.cjs +2 -2
- package/dist/modules/utils/number.js +2 -2
- package/dist/modules/utils/random.cjs +2 -2
- package/dist/modules/utils/random.js +2 -2
- package/dist/modules/utils/stagger.cjs +2 -2
- package/dist/modules/utils/stagger.js +2 -2
- package/dist/modules/utils/target.cjs +2 -2
- package/dist/modules/utils/target.js +2 -2
- package/dist/modules/utils/time.cjs +2 -2
- package/dist/modules/utils/time.js +2 -2
- package/dist/modules/waapi/composition.cjs +2 -2
- package/dist/modules/waapi/composition.js +2 -2
- package/dist/modules/waapi/index.cjs +2 -2
- package/dist/modules/waapi/index.js +2 -2
- package/dist/modules/waapi/waapi.cjs +12 -7
- package/dist/modules/waapi/waapi.js +12 -7
- package/package.json +1 -1
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Anime.js - layout - ESM
|
|
3
|
-
* @version v4.3.0
|
|
3
|
+
* @version v4.3.0
|
|
4
4
|
* @license MIT
|
|
5
|
-
* @copyright
|
|
5
|
+
* @copyright 2026 - Julian Garnier
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { mergeObjects,
|
|
8
|
+
import { mergeObjects, isUnd, isSvg, isStr, isFnc, isArr } from '../core/helpers.js';
|
|
9
9
|
import { registerTargets } from '../core/targets.js';
|
|
10
|
+
import { parseEase } from '../easings/eases/parser.js';
|
|
10
11
|
import { setValue, getFunctionValue } from '../core/values.js';
|
|
11
|
-
import { noop } from '../core/consts.js';
|
|
12
12
|
import { createTimeline } from '../timeline/timeline.js';
|
|
13
13
|
import { waapi } from '../waapi/waapi.js';
|
|
14
|
-
import { scope } from '../core/globals.js';
|
|
14
|
+
import { scope, defaults } from '../core/globals.js';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* @import {
|
|
18
18
|
* AnimationParams,
|
|
19
|
+
* RenderableCallbacks,
|
|
20
|
+
* TickableCallbacks,
|
|
21
|
+
* TimelineParams,
|
|
22
|
+
* TimerParams,
|
|
19
23
|
* } from '../types/index.js'
|
|
20
24
|
*/
|
|
21
25
|
|
|
@@ -31,13 +35,18 @@ import { scope } from '../core/globals.js';
|
|
|
31
35
|
* } from '../waapi/waapi.js'
|
|
32
36
|
*/
|
|
33
37
|
|
|
38
|
+
/**
|
|
39
|
+
* @import {
|
|
40
|
+
* Spring,
|
|
41
|
+
} from '../easings/spring/index.js'
|
|
42
|
+
*/
|
|
43
|
+
|
|
34
44
|
/**
|
|
35
45
|
* @import {
|
|
36
46
|
* DOMTarget,
|
|
37
47
|
* DOMTargetSelector,
|
|
38
48
|
* FunctionValue,
|
|
39
49
|
* EasingParam,
|
|
40
|
-
* Callback,
|
|
41
50
|
} from '../types/index.js'
|
|
42
51
|
*/
|
|
43
52
|
|
|
@@ -46,29 +55,47 @@ import { scope } from '../core/globals.js';
|
|
|
46
55
|
*/
|
|
47
56
|
|
|
48
57
|
/**
|
|
49
|
-
* @typedef {
|
|
58
|
+
* @typedef {Object} LayoutAnimationTimingsParams
|
|
59
|
+
* @property {Number|FunctionValue} [delay]
|
|
60
|
+
* @property {Number|FunctionValue} [duration]
|
|
61
|
+
* @property {EasingParam|FunctionValue} [ease]
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @typedef {Record<String, Number|String|FunctionValue>} LayoutStateAnimationProperties
|
|
50
66
|
*/
|
|
51
67
|
|
|
52
68
|
/**
|
|
53
|
-
* @typedef {
|
|
69
|
+
* @typedef {LayoutStateAnimationProperties & LayoutAnimationTimingsParams} LayoutStateParams
|
|
70
|
+
*/
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @typedef {Object} LayoutSpecificAnimationParams
|
|
54
74
|
* @property {Number|FunctionValue} [delay]
|
|
55
75
|
* @property {Number|FunctionValue} [duration]
|
|
56
|
-
* @property {EasingParam} [ease]
|
|
57
|
-
* @property {
|
|
58
|
-
* @property {LayoutStateParams} [
|
|
59
|
-
* @property {LayoutStateParams} [
|
|
60
|
-
* @property {
|
|
76
|
+
* @property {EasingParam|FunctionValue} [ease]
|
|
77
|
+
* @property {EasingParam} [playbackEase]
|
|
78
|
+
* @property {LayoutStateParams} [swapAt]
|
|
79
|
+
* @property {LayoutStateParams} [enterFrom]
|
|
80
|
+
* @property {LayoutStateParams} [leaveTo]
|
|
81
|
+
*/
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @typedef {LayoutSpecificAnimationParams & TimerParams & TickableCallbacks<Timeline> & RenderableCallbacks<Timeline>} LayoutAnimationParams
|
|
61
85
|
*/
|
|
62
86
|
|
|
63
87
|
/**
|
|
64
|
-
* @typedef {
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
* }} AutoLayoutParams
|
|
88
|
+
* @typedef {Object} LayoutOptions
|
|
89
|
+
* @property {LayoutChildrenParam} [children]
|
|
90
|
+
* @property {Array<String>} [properties]
|
|
68
91
|
*/
|
|
69
92
|
|
|
70
93
|
/**
|
|
71
|
-
* @typedef {
|
|
94
|
+
* @typedef {LayoutAnimationParams & LayoutOptions} AutoLayoutParams
|
|
95
|
+
*/
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @typedef {Record<String, Number|String|FunctionValue> & {
|
|
72
99
|
* transform: String,
|
|
73
100
|
* x: Number,
|
|
74
101
|
* y: Number,
|
|
@@ -89,13 +116,15 @@ import { scope } from '../core/globals.js';
|
|
|
89
116
|
* @property {Number} total
|
|
90
117
|
* @property {Number} delay
|
|
91
118
|
* @property {Number} duration
|
|
119
|
+
* @property {EasingParam} ease
|
|
92
120
|
* @property {DOMTarget} $measure
|
|
93
121
|
* @property {LayoutSnapshot} state
|
|
94
122
|
* @property {AutoLayout} layout
|
|
95
123
|
* @property {LayoutNode|null} parentNode
|
|
96
124
|
* @property {Boolean} isTarget
|
|
125
|
+
* @property {Boolean} isEntering
|
|
126
|
+
* @property {Boolean} isLeaving
|
|
97
127
|
* @property {Boolean} hasTransform
|
|
98
|
-
* @property {Boolean} isAnimated
|
|
99
128
|
* @property {Array<String>} inlineStyles
|
|
100
129
|
* @property {String|null} inlineTransforms
|
|
101
130
|
* @property {String|null} inlineTransition
|
|
@@ -236,7 +265,7 @@ const detachNode = node => {
|
|
|
236
265
|
* @param {DOMTarget} $el
|
|
237
266
|
* @param {LayoutNode|null} parentNode
|
|
238
267
|
* @param {LayoutSnapshot} state
|
|
239
|
-
* @param {LayoutNode}
|
|
268
|
+
* @param {LayoutNode} recycledNode
|
|
240
269
|
* @return {LayoutNode}
|
|
241
270
|
*/
|
|
242
271
|
const createNode = ($el, parentNode, state, recycledNode) => {
|
|
@@ -250,12 +279,15 @@ const createNode = ($el, parentNode, state, recycledNode) => {
|
|
|
250
279
|
node.total = 1;
|
|
251
280
|
node.delay = 0;
|
|
252
281
|
node.duration = 0;
|
|
282
|
+
node.ease = null;
|
|
253
283
|
node.state = state;
|
|
254
284
|
node.layout = state.layout;
|
|
255
285
|
node.parentNode = parentNode || null;
|
|
256
286
|
node.isTarget = false;
|
|
287
|
+
node.isEntering = false;
|
|
288
|
+
node.isLeaving = false;
|
|
289
|
+
node.isInlined = false;
|
|
257
290
|
node.hasTransform = false;
|
|
258
|
-
node.isAnimated = false;
|
|
259
291
|
node.inlineStyles = [];
|
|
260
292
|
node.inlineTransforms = null;
|
|
261
293
|
node.inlineTransition = null;
|
|
@@ -263,7 +295,6 @@ const createNode = ($el, parentNode, state, recycledNode) => {
|
|
|
263
295
|
node.branchRemoved = false;
|
|
264
296
|
node.branchNotRendered = false;
|
|
265
297
|
node.sizeChanged = false;
|
|
266
|
-
node.isInlined = false;
|
|
267
298
|
node.hasVisibilitySwap = false;
|
|
268
299
|
node.hasDisplayNone = false;
|
|
269
300
|
node.hasVisibilityHidden = false;
|
|
@@ -406,7 +437,7 @@ const recordNodeState = (node, $measure, computedStyle, skipMeasurements) => {
|
|
|
406
437
|
|
|
407
438
|
/**
|
|
408
439
|
* @param {LayoutNode} node
|
|
409
|
-
* @param {
|
|
440
|
+
* @param {LayoutStateAnimationProperties} [props]
|
|
410
441
|
*/
|
|
411
442
|
const updateNodeProperties = (node, props) => {
|
|
412
443
|
if (!props) return;
|
|
@@ -415,6 +446,19 @@ const updateNodeProperties = (node, props) => {
|
|
|
415
446
|
}
|
|
416
447
|
};
|
|
417
448
|
|
|
449
|
+
/**
|
|
450
|
+
* @param {LayoutNode} node
|
|
451
|
+
* @param {LayoutAnimationTimingsParams} params
|
|
452
|
+
*/
|
|
453
|
+
const updateNodeTimingParams = (node, params) => {
|
|
454
|
+
const easeFunctionResult = getFunctionValue(params.ease, node.$el, node.index, node.total);
|
|
455
|
+
const keyEasing = isFnc(easeFunctionResult) ? easeFunctionResult : params.ease;
|
|
456
|
+
const hasSpring = !isUnd(keyEasing) && !isUnd(/** @type {Spring} */(keyEasing).ease);
|
|
457
|
+
node.ease = hasSpring ? /** @type {Spring} */(keyEasing).ease : keyEasing;
|
|
458
|
+
node.duration = hasSpring ? /** @type {Spring} */(keyEasing).settlingDuration : getFunctionValue(params.duration, node.$el, node.index, node.total);
|
|
459
|
+
node.delay = getFunctionValue(params.delay, node.$el, node.index, node.total);
|
|
460
|
+
};
|
|
461
|
+
|
|
418
462
|
/**
|
|
419
463
|
* @param {LayoutNode} node
|
|
420
464
|
*/
|
|
@@ -489,9 +533,9 @@ const restoreNodeVisualState = node => {
|
|
|
489
533
|
node.$measure.style.removeProperty('visibility');
|
|
490
534
|
}
|
|
491
535
|
}
|
|
492
|
-
if (node.measuredIsRemoved) {
|
|
493
|
-
|
|
494
|
-
}
|
|
536
|
+
// if (node.measuredIsRemoved) {
|
|
537
|
+
node.layout.pendingRemoval.delete(node.$el);
|
|
538
|
+
// }
|
|
495
539
|
};
|
|
496
540
|
|
|
497
541
|
/**
|
|
@@ -541,6 +585,7 @@ class LayoutSnapshot {
|
|
|
541
585
|
*/
|
|
542
586
|
revert() {
|
|
543
587
|
this.forEachNode(node => {
|
|
588
|
+
this.layout.pendingRemoval.delete(node.$el);
|
|
544
589
|
node.$el.removeAttribute('data-layout-id');
|
|
545
590
|
node.$measure.removeAttribute('data-layout-id');
|
|
546
591
|
});
|
|
@@ -552,34 +597,22 @@ class LayoutSnapshot {
|
|
|
552
597
|
|
|
553
598
|
/**
|
|
554
599
|
* @param {DOMTarget} $el
|
|
555
|
-
* @return {
|
|
600
|
+
* @return {LayoutNode}
|
|
556
601
|
*/
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
console.warn(`No node found on state`);
|
|
561
|
-
return;
|
|
562
|
-
}
|
|
563
|
-
return node.properties;
|
|
602
|
+
getNode($el) {
|
|
603
|
+
if (!$el || !$el.dataset) return;
|
|
604
|
+
return this.nodes.get($el.dataset.layoutId);
|
|
564
605
|
}
|
|
565
606
|
|
|
566
607
|
/**
|
|
567
608
|
* @param {DOMTarget} $el
|
|
568
609
|
* @param {String} prop
|
|
569
|
-
* @return {Number|String
|
|
610
|
+
* @return {Number|String}
|
|
570
611
|
*/
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
}
|
|
576
|
-
const node = this.nodes.get($el.dataset.layoutId);
|
|
577
|
-
if (!node) {
|
|
578
|
-
console.warn(`No node found on state`);
|
|
579
|
-
return;
|
|
580
|
-
}
|
|
581
|
-
const value = node.properties[prop];
|
|
582
|
-
if (!isUnd(value)) return getFunctionValue(value, $el, node.index, node.total);
|
|
612
|
+
getComputedValue($el, prop) {
|
|
613
|
+
const node = this.getNode($el);
|
|
614
|
+
if (!node) return;
|
|
615
|
+
return /** @type {Number|String} */(node.properties[prop]);
|
|
583
616
|
}
|
|
584
617
|
|
|
585
618
|
/**
|
|
@@ -640,10 +673,10 @@ class LayoutSnapshot {
|
|
|
640
673
|
const $parent = /** @type {LayoutNode|null} */(stack.pop());
|
|
641
674
|
/** @type {DOMTarget|null} */
|
|
642
675
|
const $current = /** @type {DOMTarget|null} */(stack.pop());
|
|
676
|
+
|
|
643
677
|
if (!$current || $current.nodeType !== 1 || isSvg($current)) continue;
|
|
644
678
|
|
|
645
679
|
const skipMeasurements = $parent ? $parent.measuredIsRemoved : false;
|
|
646
|
-
|
|
647
680
|
const computedStyle = skipMeasurements ? hiddenComputedStyle : getComputedStyle($current);
|
|
648
681
|
const hasDisplayNone = skipMeasurements ? true : computedStyle.display === 'none';
|
|
649
682
|
const hasVisibilityHidden = skipMeasurements ? true : computedStyle.visibility === 'hidden';
|
|
@@ -690,11 +723,10 @@ class LayoutSnapshot {
|
|
|
690
723
|
node.branchRemoved = false;
|
|
691
724
|
node.branchNotRendered = false;
|
|
692
725
|
node.isTarget = false;
|
|
693
|
-
node.
|
|
726
|
+
node.sizeChanged = false;
|
|
694
727
|
node.hasVisibilityHidden = hasVisibilityHidden;
|
|
695
728
|
node.hasDisplayNone = hasDisplayNone;
|
|
696
729
|
node.hasVisibilitySwap = (hasVisibilityHidden && !node.measuredHasVisibilityHidden) || (hasDisplayNone && !node.measuredHasDisplayNone);
|
|
697
|
-
// node.hasVisibilitySwap = (hasVisibilityHidden !== node.measuredHasVisibilityHidden) || (hasDisplayNone !== node.measuredHasDisplayNone);
|
|
698
730
|
|
|
699
731
|
this.nodes.set(node.id, node);
|
|
700
732
|
|
|
@@ -713,6 +745,7 @@ class LayoutSnapshot {
|
|
|
713
745
|
$parent._tail = node;
|
|
714
746
|
}
|
|
715
747
|
} else {
|
|
748
|
+
// Each disconnected subtree becomes its own root in the snapshot graph
|
|
716
749
|
this.rootNodes.add(node);
|
|
717
750
|
}
|
|
718
751
|
|
|
@@ -756,11 +789,29 @@ class LayoutSnapshot {
|
|
|
756
789
|
* @return {this}
|
|
757
790
|
*/
|
|
758
791
|
record() {
|
|
759
|
-
const
|
|
792
|
+
const layout = this.layout;
|
|
793
|
+
const children = layout.children;
|
|
794
|
+
const root = layout.root;
|
|
760
795
|
const toParse = isArr(children) ? children : [children];
|
|
761
796
|
const scoped = [];
|
|
762
797
|
const scopeRoot = children === '*' ? root : scope.root;
|
|
763
798
|
|
|
799
|
+
// Mute transition and transforms of root ancestors before recording the state
|
|
800
|
+
|
|
801
|
+
/** @type {Array<DOMTarget|String|null>} */
|
|
802
|
+
const rootAncestorTransformStore = [];
|
|
803
|
+
let $ancestor = root.parentElement;
|
|
804
|
+
while ($ancestor && $ancestor.nodeType === 1) {
|
|
805
|
+
const computedStyle = getComputedStyle($ancestor);
|
|
806
|
+
if (computedStyle.transform && computedStyle.transform !== 'none') {
|
|
807
|
+
const inlineTransform = $ancestor.style.transform || '';
|
|
808
|
+
const inlineTransition = muteElementTransition($ancestor);
|
|
809
|
+
rootAncestorTransformStore.push($ancestor, inlineTransform, inlineTransition);
|
|
810
|
+
$ancestor.style.transform = 'none';
|
|
811
|
+
}
|
|
812
|
+
$ancestor = $ancestor.parentElement;
|
|
813
|
+
}
|
|
814
|
+
|
|
764
815
|
for (let i = 0, l = toParse.length; i < l; i++) {
|
|
765
816
|
const child = toParse[i];
|
|
766
817
|
scoped[i] = isStr(child) ? scopeRoot.querySelectorAll(child) : child;
|
|
@@ -776,9 +827,13 @@ class LayoutSnapshot {
|
|
|
776
827
|
rootNode.isTarget = true;
|
|
777
828
|
this.rootNode = rootNode;
|
|
778
829
|
|
|
779
|
-
// Track ids of nodes that belong to the current root to filter detached matches
|
|
780
830
|
const inRootNodeIds = new Set();
|
|
831
|
+
// Update index and total for inital timing calculation
|
|
832
|
+
let index = 0, total = this.nodes.size;
|
|
781
833
|
this.nodes.forEach((node, id) => {
|
|
834
|
+
node.index = index++;
|
|
835
|
+
node.total = total;
|
|
836
|
+
// Track ids of nodes that belong to the current root to filter detached matches
|
|
782
837
|
if (node && node.measuredIsInsideRoot) {
|
|
783
838
|
inRootNodeIds.add(id);
|
|
784
839
|
}
|
|
@@ -808,7 +863,7 @@ class LayoutSnapshot {
|
|
|
808
863
|
|
|
809
864
|
for (let i = 0, l = parsedChildren.length; i < l; i++) {
|
|
810
865
|
const $el = parsedChildren[i];
|
|
811
|
-
const node = this.
|
|
866
|
+
const node = this.getNode($el);
|
|
812
867
|
if (node) {
|
|
813
868
|
let cur = node;
|
|
814
869
|
while (cur) {
|
|
@@ -822,18 +877,52 @@ class LayoutSnapshot {
|
|
|
822
877
|
this.scrollX = window.scrollX;
|
|
823
878
|
this.scrollY = window.scrollY;
|
|
824
879
|
|
|
825
|
-
const total = this.nodes.size;
|
|
826
|
-
|
|
827
880
|
this.forEachNode(restoreNodeTransform);
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
881
|
+
|
|
882
|
+
// Restore transition and transforms of root ancestors
|
|
883
|
+
|
|
884
|
+
for (let i = 0, l = rootAncestorTransformStore.length; i < l; i += 3) {
|
|
885
|
+
const $el = /** @type {DOMTarget} */(rootAncestorTransformStore[i]);
|
|
886
|
+
const inlineTransform = /** @type {String} */(rootAncestorTransformStore[i + 1]);
|
|
887
|
+
const inlineTransition = /** @type {String|null} */(rootAncestorTransformStore[i + 2]);
|
|
888
|
+
if (inlineTransform && inlineTransform !== '') {
|
|
889
|
+
$el.style.transform = inlineTransform;
|
|
890
|
+
} else {
|
|
891
|
+
$el.style.removeProperty('transform');
|
|
892
|
+
}
|
|
893
|
+
restoreElementTransition($el, inlineTransition);
|
|
894
|
+
}
|
|
832
895
|
|
|
833
896
|
return this;
|
|
834
897
|
}
|
|
835
898
|
}
|
|
836
899
|
|
|
900
|
+
/**
|
|
901
|
+
* @param {LayoutStateParams} params
|
|
902
|
+
* @return {[LayoutStateAnimationProperties, LayoutAnimationTimingsParams]}
|
|
903
|
+
*/
|
|
904
|
+
function splitPropertiesFromParams(params) {
|
|
905
|
+
/** @type {LayoutStateAnimationProperties} */
|
|
906
|
+
const properties = {};
|
|
907
|
+
/** @type {LayoutAnimationTimingsParams} */
|
|
908
|
+
const parameters = {};
|
|
909
|
+
for (let name in params) {
|
|
910
|
+
const value = params[name];
|
|
911
|
+
const isEase = name === 'ease';
|
|
912
|
+
const isTiming = name === 'duration' || name === 'delay';
|
|
913
|
+
if (isTiming || isEase) {
|
|
914
|
+
if (isEase) {
|
|
915
|
+
parameters[name] = /** @type {EasingParam} */(value);
|
|
916
|
+
} else {
|
|
917
|
+
parameters[name] = /** @type {Number|FunctionValue} */(value);
|
|
918
|
+
}
|
|
919
|
+
} else {
|
|
920
|
+
properties[name] = /** @type {Number|String} */(value);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
return [properties, parameters];
|
|
924
|
+
}
|
|
925
|
+
|
|
837
926
|
class AutoLayout {
|
|
838
927
|
/**
|
|
839
928
|
* @param {DOMTargetSelector} root
|
|
@@ -841,10 +930,16 @@ class AutoLayout {
|
|
|
841
930
|
*/
|
|
842
931
|
constructor(root, params = {}) {
|
|
843
932
|
if (scope.current) scope.current.register(this);
|
|
844
|
-
const
|
|
845
|
-
const
|
|
846
|
-
const
|
|
847
|
-
const
|
|
933
|
+
const swapAtSplitParams = splitPropertiesFromParams(params.swapAt);
|
|
934
|
+
const enterFromSplitParams = splitPropertiesFromParams(params.enterFrom);
|
|
935
|
+
const leaveToSplitParams = splitPropertiesFromParams(params.leaveTo);
|
|
936
|
+
const transitionProperties = params.properties;
|
|
937
|
+
/** @type {Number|FunctionValue} */
|
|
938
|
+
params.duration = setValue(params.duration, 350);
|
|
939
|
+
/** @type {Number|FunctionValue} */
|
|
940
|
+
params.delay = setValue(params.delay, 0);
|
|
941
|
+
/** @type {EasingParam|FunctionValue} */
|
|
942
|
+
params.ease = setValue(params.ease, 'inOut(3.5)');
|
|
848
943
|
/** @type {AutoLayoutParams} */
|
|
849
944
|
this.params = params;
|
|
850
945
|
/** @type {DOMTarget} */
|
|
@@ -855,29 +950,27 @@ class AutoLayout {
|
|
|
855
950
|
this.children = params.children || '*';
|
|
856
951
|
/** @type {Boolean} */
|
|
857
952
|
this.absoluteCoords = false;
|
|
858
|
-
/** @type {Number|FunctionValue} */
|
|
859
|
-
this.duration = setValue(params.duration, 500);
|
|
860
|
-
/** @type {Number|FunctionValue} */
|
|
861
|
-
this.delay = setValue(params.delay, 0);
|
|
862
|
-
/** @type {EasingParam} */
|
|
863
|
-
this.ease = setValue(params.ease, 'inOut(3.5)');
|
|
864
|
-
/** @type {Callback<this>} */
|
|
865
|
-
this.onComplete = setValue(params.onComplete, /** @type {Callback<this>} */(noop));
|
|
866
953
|
/** @type {LayoutStateParams} */
|
|
867
|
-
this.
|
|
954
|
+
this.swapAtParams = mergeObjects(params.swapAt || { opacity: 0 }, { ease: 'inOut(1.75)' });
|
|
868
955
|
/** @type {LayoutStateParams} */
|
|
869
|
-
this.
|
|
956
|
+
this.enterFromParams = params.enterFrom || { opacity: 0 };
|
|
870
957
|
/** @type {LayoutStateParams} */
|
|
871
|
-
this.
|
|
958
|
+
this.leaveToParams = params.leaveTo || { opacity: 0 };
|
|
872
959
|
/** @type {Set<String>} */
|
|
873
960
|
this.properties = new Set([
|
|
874
961
|
'opacity',
|
|
962
|
+
'fontSize',
|
|
963
|
+
'color',
|
|
964
|
+
'backgroundColor',
|
|
875
965
|
'borderRadius',
|
|
966
|
+
'border',
|
|
967
|
+
'filter',
|
|
968
|
+
'clipPath',
|
|
876
969
|
]);
|
|
877
|
-
if (
|
|
878
|
-
if (
|
|
879
|
-
if (
|
|
880
|
-
if (
|
|
970
|
+
if (swapAtSplitParams[0]) for (let name in swapAtSplitParams[0]) this.properties.add(name);
|
|
971
|
+
if (enterFromSplitParams[0]) for (let name in enterFromSplitParams[0]) this.properties.add(name);
|
|
972
|
+
if (leaveToSplitParams[0]) for (let name in leaveToSplitParams[0]) this.properties.add(name);
|
|
973
|
+
if (transitionProperties) for (let i = 0, l = transitionProperties.length; i < l; i++) this.properties.add(transitionProperties[i]);
|
|
881
974
|
/** @type {Set<String>} */
|
|
882
975
|
this.recordedProperties = new Set([
|
|
883
976
|
'display',
|
|
@@ -897,24 +990,26 @@ class AutoLayout {
|
|
|
897
990
|
]);
|
|
898
991
|
this.properties.forEach(prop => this.recordedProperties.add(prop));
|
|
899
992
|
/** @type {WeakSet<DOMTarget>} */
|
|
900
|
-
this.
|
|
993
|
+
this.pendingRemoval = new WeakSet();
|
|
901
994
|
/** @type {Map<DOMTarget, String|null>} */
|
|
902
995
|
this.transitionMuteStore = new Map();
|
|
903
996
|
/** @type {LayoutSnapshot} */
|
|
904
997
|
this.oldState = new LayoutSnapshot(this);
|
|
905
998
|
/** @type {LayoutSnapshot} */
|
|
906
999
|
this.newState = new LayoutSnapshot(this);
|
|
907
|
-
/** @type {Timeline
|
|
1000
|
+
/** @type {Timeline} */
|
|
908
1001
|
this.timeline = null;
|
|
909
|
-
/** @type {WAAPIAnimation
|
|
1002
|
+
/** @type {WAAPIAnimation} */
|
|
910
1003
|
this.transformAnimation = null;
|
|
911
1004
|
/** @type {Array<DOMTarget>} */
|
|
912
|
-
this.
|
|
1005
|
+
this.animating = [];
|
|
1006
|
+
/** @type {Array<DOMTarget>} */
|
|
1007
|
+
this.swapping = [];
|
|
913
1008
|
/** @type {Array<DOMTarget>} */
|
|
914
|
-
this.
|
|
1009
|
+
this.leaving = [];
|
|
915
1010
|
/** @type {Array<DOMTarget>} */
|
|
916
|
-
this.
|
|
917
|
-
// Record the current state as the old state to init the data attributes
|
|
1011
|
+
this.entering = [];
|
|
1012
|
+
// Record the current state as the old state to init the data attributes and allow imediate .animate()
|
|
918
1013
|
this.oldState.record();
|
|
919
1014
|
// And all layout transition muted during the record
|
|
920
1015
|
restoreLayoutTransition(this.transitionMuteStore);
|
|
@@ -924,6 +1019,7 @@ class AutoLayout {
|
|
|
924
1019
|
* @return {this}
|
|
925
1020
|
*/
|
|
926
1021
|
revert() {
|
|
1022
|
+
this.root.classList.remove('is-animated');
|
|
927
1023
|
if (this.timeline) {
|
|
928
1024
|
this.timeline.complete();
|
|
929
1025
|
this.timeline = null;
|
|
@@ -932,8 +1028,7 @@ class AutoLayout {
|
|
|
932
1028
|
this.transformAnimation.complete();
|
|
933
1029
|
this.transformAnimation = null;
|
|
934
1030
|
}
|
|
935
|
-
this.
|
|
936
|
-
this.frozen.length = this.removed.length = this.added.length = 0;
|
|
1031
|
+
this.animating.length = this.swapping.length = this.leaving.length = this.entering.length = 0;
|
|
937
1032
|
this.oldState.revert();
|
|
938
1033
|
this.newState.revert();
|
|
939
1034
|
requestAnimationFrame(() => restoreLayoutTransition(this.transitionMuteStore));
|
|
@@ -966,20 +1061,72 @@ class AutoLayout {
|
|
|
966
1061
|
* @return {Timeline}
|
|
967
1062
|
*/
|
|
968
1063
|
animate(params = {}) {
|
|
969
|
-
|
|
970
|
-
const
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1064
|
+
/** @type { LayoutAnimationTimingsParams } */
|
|
1065
|
+
const animationTimings = {
|
|
1066
|
+
ease: setValue(params.ease, this.params.ease),
|
|
1067
|
+
delay: setValue(params.delay, this.params.delay),
|
|
1068
|
+
duration: setValue(params.duration, this.params.duration),
|
|
1069
|
+
};
|
|
1070
|
+
/** @type {TimelineParams} */
|
|
1071
|
+
const tlParams = {};
|
|
1072
|
+
const onComplete = setValue(params.onComplete, this.params.onComplete);
|
|
1073
|
+
const onPause = setValue(params.onPause, this.params.onPause);
|
|
1074
|
+
for (let name in defaults) {
|
|
1075
|
+
if (name !== 'ease' && name !== 'duration' && name !== 'delay') {
|
|
1076
|
+
if (!isUnd(params[name])) {
|
|
1077
|
+
tlParams[name] = params[name];
|
|
1078
|
+
} else if (!isUnd(this.params[name])) {
|
|
1079
|
+
tlParams[name] = this.params[name];
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
tlParams.onComplete = () => {
|
|
1084
|
+
// Make sure to call .cancel() after restoreNodeInlineStyles(node); otehrwise the commited styles get reverted
|
|
1085
|
+
if (this.transformAnimation) this.transformAnimation.cancel();
|
|
1086
|
+
newState.forEachRootNode(node => {
|
|
1087
|
+
restoreNodeVisualState(node);
|
|
1088
|
+
restoreNodeInlineStyles(node);
|
|
1089
|
+
});
|
|
1090
|
+
for (let i = 0, l = transformed.length; i < l; i++) {
|
|
1091
|
+
const $el = transformed[i];
|
|
1092
|
+
$el.style.transform = newState.getComputedValue($el, 'transform');
|
|
1093
|
+
}
|
|
1094
|
+
if (this.root.classList.contains('is-animated')) {
|
|
1095
|
+
this.root.classList.remove('is-animated');
|
|
1096
|
+
if (onComplete) onComplete(this.timeline);
|
|
1097
|
+
}
|
|
1098
|
+
// Avoid CSS transitions at the end of the animation by restoring them on the next frame
|
|
1099
|
+
requestAnimationFrame(() => {
|
|
1100
|
+
if (this.root.classList.contains('is-animated')) return;
|
|
1101
|
+
restoreLayoutTransition(this.transitionMuteStore);
|
|
1102
|
+
});
|
|
1103
|
+
};
|
|
1104
|
+
tlParams.onPause = () => {
|
|
1105
|
+
if (!this.root.classList.contains('is-animated')) return;
|
|
1106
|
+
if (this.transformAnimation) this.transformAnimation.cancel();
|
|
1107
|
+
newState.forEachRootNode(restoreNodeVisualState);
|
|
1108
|
+
this.root.classList.remove('is-animated');
|
|
1109
|
+
if (onComplete) onComplete(this.timeline);
|
|
1110
|
+
if (onPause) onPause(this.timeline);
|
|
1111
|
+
};
|
|
1112
|
+
tlParams.composition = false;
|
|
1113
|
+
|
|
1114
|
+
const swapAtParams = mergeObjects(mergeObjects(params.swapAt || {}, this.swapAtParams), animationTimings);
|
|
1115
|
+
const enterFromParams = mergeObjects(mergeObjects(params.enterFrom || {}, this.enterFromParams), animationTimings);
|
|
1116
|
+
const leaveToParams = mergeObjects(mergeObjects(params.leaveTo || {}, this.leaveToParams), animationTimings);
|
|
1117
|
+
const [ swapAtProps, swapAtTimings ] = splitPropertiesFromParams(swapAtParams);
|
|
1118
|
+
const [ enterFromProps, enterFromTimings ] = splitPropertiesFromParams(enterFromParams);
|
|
1119
|
+
const [ leaveToProps, leaveToTimings ] = splitPropertiesFromParams(leaveToParams);
|
|
1120
|
+
|
|
975
1121
|
const oldState = this.oldState;
|
|
976
1122
|
const newState = this.newState;
|
|
977
|
-
const
|
|
978
|
-
const
|
|
979
|
-
const
|
|
980
|
-
const
|
|
1123
|
+
const animating = this.animating;
|
|
1124
|
+
const swapping = this.swapping;
|
|
1125
|
+
const entering = this.entering;
|
|
1126
|
+
const leaving = this.leaving;
|
|
1127
|
+
const pendingRemoval = this.pendingRemoval;
|
|
981
1128
|
|
|
982
|
-
|
|
1129
|
+
animating.length = swapping.length = entering.length = leaving.length = 0;
|
|
983
1130
|
|
|
984
1131
|
// Mute old state CSS transitions to prevent wrong properties calculation
|
|
985
1132
|
oldState.forEachRootNode(muteNodeTransition);
|
|
@@ -990,10 +1137,12 @@ class AutoLayout {
|
|
|
990
1137
|
const targets = [];
|
|
991
1138
|
const animated = [];
|
|
992
1139
|
const transformed = [];
|
|
993
|
-
const
|
|
994
|
-
const
|
|
1140
|
+
const animatedSwap = [];
|
|
1141
|
+
const rootNode = newState.rootNode;
|
|
1142
|
+
const $root = rootNode.$el;
|
|
995
1143
|
|
|
996
1144
|
newState.forEachRootNode(node => {
|
|
1145
|
+
|
|
997
1146
|
const $el = node.$el;
|
|
998
1147
|
const id = node.id;
|
|
999
1148
|
const parent = node.parentNode;
|
|
@@ -1001,10 +1150,6 @@ class AutoLayout {
|
|
|
1001
1150
|
const parentRemoved = parent ? parent.branchRemoved : false;
|
|
1002
1151
|
const parentNotRendered = parent ? parent.branchNotRendered : false;
|
|
1003
1152
|
|
|
1004
|
-
// Delay and duration must be calculated in the animate() call to support delay override
|
|
1005
|
-
node.delay = +(isFnc(delay) ? delay($el, node.index, node.total) : delay);
|
|
1006
|
-
node.duration = +(isFnc(duration) ? duration($el, node.index, node.total) : duration);
|
|
1007
|
-
|
|
1008
1153
|
let oldStateNode = oldState.nodes.get(id);
|
|
1009
1154
|
|
|
1010
1155
|
const hasNoOldState = !oldStateNode;
|
|
@@ -1054,7 +1199,7 @@ class AutoLayout {
|
|
|
1054
1199
|
}
|
|
1055
1200
|
}
|
|
1056
1201
|
|
|
1057
|
-
const wasPendingRemoval =
|
|
1202
|
+
const wasPendingRemoval = pendingRemoval.has($el);
|
|
1058
1203
|
const wasVisibleBefore = oldStateNode.measuredIsVisible;
|
|
1059
1204
|
const isVisibleNow = node.measuredIsVisible;
|
|
1060
1205
|
const becomeVisible = !wasVisibleBefore && isVisibleNow && !parentNotRendered;
|
|
@@ -1062,113 +1207,156 @@ class AutoLayout {
|
|
|
1062
1207
|
const newlyRemoved = isRemovedNow && !wasRemovedBefore && !parentRemoved;
|
|
1063
1208
|
const topLevelRemoved = newlyRemoved || isRemovedNow && wasPendingRemoval && !parentRemoved;
|
|
1064
1209
|
|
|
1065
|
-
|
|
1210
|
+
node.branchAdded = parentAdded || topLevelAdded;
|
|
1211
|
+
node.branchRemoved = parentRemoved || topLevelRemoved;
|
|
1212
|
+
node.branchNotRendered = parentNotRendered || isRemovedNow;
|
|
1213
|
+
|
|
1214
|
+
if (isRemovedNow && wasVisibleBefore) {
|
|
1066
1215
|
node.$el.style.display = oldStateNode.measuredDisplay;
|
|
1067
1216
|
node.$el.style.visibility = 'visible';
|
|
1068
1217
|
cloneNodeProperties(oldStateNode, node, newState);
|
|
1069
1218
|
}
|
|
1070
1219
|
|
|
1220
|
+
// Node is leaving
|
|
1071
1221
|
if (newlyRemoved) {
|
|
1072
|
-
|
|
1073
|
-
|
|
1222
|
+
if (node.isTarget) {
|
|
1223
|
+
leaving.push($el);
|
|
1224
|
+
node.isLeaving = true;
|
|
1225
|
+
}
|
|
1226
|
+
pendingRemoval.add($el);
|
|
1074
1227
|
} else if (!isRemovedNow && wasPendingRemoval) {
|
|
1075
|
-
|
|
1228
|
+
pendingRemoval.delete($el);
|
|
1076
1229
|
}
|
|
1077
1230
|
|
|
1078
|
-
// Node is
|
|
1231
|
+
// Node is entering
|
|
1079
1232
|
if ((topLevelAdded && !parentNotRendered) || becomeVisible) {
|
|
1080
|
-
updateNodeProperties(oldStateNode,
|
|
1081
|
-
|
|
1082
|
-
|
|
1233
|
+
updateNodeProperties(oldStateNode, enterFromProps);
|
|
1234
|
+
if (node.isTarget) {
|
|
1235
|
+
entering.push($el);
|
|
1236
|
+
node.isEntering = true;
|
|
1237
|
+
}
|
|
1238
|
+
// Node is leaving
|
|
1083
1239
|
} else if (topLevelRemoved && !parentNotRendered) {
|
|
1084
|
-
updateNodeProperties(node,
|
|
1240
|
+
updateNodeProperties(node, leaveToProps);
|
|
1085
1241
|
}
|
|
1086
1242
|
|
|
1087
|
-
//
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
oldStateNode.properties[name] = oldState.getValue(node.$el, name);
|
|
1243
|
+
// Node is animating
|
|
1244
|
+
// The animating array is used only to calculate delays and duration on root children
|
|
1245
|
+
if (node !== rootNode && node.isTarget && !node.isEntering && !node.isLeaving) {
|
|
1246
|
+
animating.push($el);
|
|
1092
1247
|
}
|
|
1093
1248
|
|
|
1094
|
-
|
|
1095
|
-
let propertyChanged = false;
|
|
1249
|
+
targets.push($el);
|
|
1096
1250
|
|
|
1251
|
+
});
|
|
1097
1252
|
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1253
|
+
let enteringIndex = 0;
|
|
1254
|
+
let leavingIndex = 0;
|
|
1255
|
+
let animatingIndex = 0;
|
|
1256
|
+
|
|
1257
|
+
newState.forEachRootNode(node => {
|
|
1258
|
+
|
|
1259
|
+
const $el = node.$el;
|
|
1260
|
+
const parent = node.parentNode;
|
|
1261
|
+
const oldStateNode = oldState.nodes.get(node.id);
|
|
1262
|
+
const nodeProperties = node.properties;
|
|
1263
|
+
const oldStateNodeProperties = oldStateNode.properties;
|
|
1264
|
+
|
|
1265
|
+
// Use closest animated parent index and total values so that children staggered delays are in sync with their parent
|
|
1266
|
+
let animatedParent = parent !== rootNode && parent;
|
|
1267
|
+
while (animatedParent && !animatedParent.isTarget && animatedParent !== rootNode) {
|
|
1268
|
+
animatedParent = animatedParent.parentNode;
|
|
1111
1269
|
}
|
|
1112
1270
|
|
|
1113
|
-
const
|
|
1114
|
-
|
|
1271
|
+
const animatingTotal = animating.length;
|
|
1272
|
+
|
|
1273
|
+
// Root is always animated first in sync with the first child (animating.length is the total of children)
|
|
1274
|
+
if (node === rootNode) {
|
|
1275
|
+
node.index = 0;
|
|
1276
|
+
node.total = animatingTotal;
|
|
1277
|
+
updateNodeTimingParams(node, animationTimings);
|
|
1278
|
+
} else if (node.isEntering) {
|
|
1279
|
+
node.index = animatedParent ? animatedParent.index : enteringIndex;
|
|
1280
|
+
node.total = animatedParent ? animatingTotal : entering.length;
|
|
1281
|
+
updateNodeTimingParams(node, enterFromTimings);
|
|
1282
|
+
enteringIndex++;
|
|
1283
|
+
} else if (node.isLeaving) {
|
|
1284
|
+
node.index = animatedParent ? animatedParent.index : leavingIndex;
|
|
1285
|
+
node.total = animatedParent ? animatingTotal : leaving.length;
|
|
1286
|
+
leavingIndex++;
|
|
1287
|
+
updateNodeTimingParams(node, leaveToTimings);
|
|
1288
|
+
} else if (node.isTarget) {
|
|
1289
|
+
node.index = animatingIndex++;
|
|
1290
|
+
node.total = animatingTotal;
|
|
1291
|
+
updateNodeTimingParams(node, animationTimings);
|
|
1292
|
+
} else {
|
|
1293
|
+
node.index = animatedParent ? animatedParent.index : 0;
|
|
1294
|
+
node.total = animatingTotal;
|
|
1295
|
+
updateNodeTimingParams(node, swapAtTimings);
|
|
1296
|
+
}
|
|
1115
1297
|
|
|
1116
|
-
node
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
node.branchNotRendered = parentNotRendered || node.measuredIsRemoved;
|
|
1298
|
+
// Make sure the old state node has its inex and total values up to date for valid "from" function values calculation
|
|
1299
|
+
oldStateNode.index = node.index;
|
|
1300
|
+
oldStateNode.total = node.total;
|
|
1120
1301
|
|
|
1302
|
+
// Computes all values up front so we can check for changes and we don't have to re-compute them inside the animation props
|
|
1303
|
+
for (let prop in nodeProperties) {
|
|
1304
|
+
nodeProperties[prop] = getFunctionValue(nodeProperties[prop], $el, node.index, node.total);
|
|
1305
|
+
oldStateNodeProperties[prop] = getFunctionValue(oldStateNodeProperties[prop], $el, oldStateNode.index, oldStateNode.total);
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
// Use a 1px tolerance to detect dimensions changes to prevent width / height animations on barelly visible elements
|
|
1121
1309
|
const sizeTolerance = 1;
|
|
1122
|
-
const widthChanged = Math.abs(
|
|
1123
|
-
const heightChanged = Math.abs(
|
|
1310
|
+
const widthChanged = Math.abs(nodeProperties.width - oldStateNodeProperties.width) > sizeTolerance;
|
|
1311
|
+
const heightChanged = Math.abs(nodeProperties.height - oldStateNodeProperties.height) > sizeTolerance;
|
|
1124
1312
|
|
|
1125
1313
|
node.sizeChanged = (widthChanged || heightChanged);
|
|
1126
1314
|
|
|
1127
|
-
|
|
1315
|
+
// const hiddenStateChanged = (topLevelAdded || newlyRemoved) && wasRemovedBefore !== isRemovedNow;
|
|
1316
|
+
|
|
1317
|
+
if (node.isTarget && (!node.measuredIsRemoved && oldStateNode.measuredIsVisible || node.measuredIsRemoved && node.measuredIsVisible)) {
|
|
1318
|
+
if (!node.isInlined && (nodeProperties.transform !== 'none' || oldStateNodeProperties.transform !== 'none')) {
|
|
1319
|
+
node.hasTransform = true;
|
|
1320
|
+
transformed.push($el);
|
|
1321
|
+
}
|
|
1322
|
+
for (let prop in nodeProperties) {
|
|
1323
|
+
// if (prop !== 'transform' && (nodeProperties[prop] !== oldStateNodeProperties[prop] || hiddenStateChanged)) {
|
|
1324
|
+
if (prop !== 'transform' && (nodeProperties[prop] !== oldStateNodeProperties[prop])) {
|
|
1325
|
+
animated.push($el);
|
|
1326
|
+
break;
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1128
1330
|
|
|
1129
1331
|
if (!node.isTarget) {
|
|
1130
|
-
|
|
1131
|
-
if (
|
|
1132
|
-
|
|
1332
|
+
swapping.push($el);
|
|
1333
|
+
if (node.sizeChanged && parent && parent.isTarget && parent.sizeChanged) {
|
|
1334
|
+
if (!node.isInlined && swapAtProps.transform) {
|
|
1335
|
+
node.hasTransform = true;
|
|
1336
|
+
transformed.push($el);
|
|
1337
|
+
}
|
|
1338
|
+
animatedSwap.push($el);
|
|
1133
1339
|
}
|
|
1134
1340
|
}
|
|
1341
|
+
|
|
1135
1342
|
});
|
|
1136
1343
|
|
|
1137
|
-
const
|
|
1138
|
-
|
|
1139
|
-
duration: (/** @type {HTMLElement} */$el) => newState.
|
|
1140
|
-
|
|
1344
|
+
const timingParams = {
|
|
1345
|
+
delay: (/** @type {HTMLElement} */$el) => newState.getNode($el).delay,
|
|
1346
|
+
duration: (/** @type {HTMLElement} */$el) => newState.getNode($el).duration,
|
|
1347
|
+
ease: (/** @type {HTMLElement} */$el) => newState.getNode($el).ease,
|
|
1141
1348
|
};
|
|
1142
1349
|
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
$el.style.transform = newState.getValue($el, 'transform');
|
|
1154
|
-
}
|
|
1155
|
-
this.root.classList.remove('is-animated');
|
|
1156
|
-
if (onComplete) onComplete(this);
|
|
1157
|
-
// Avoid CSS transitions at the end of the animation by restoring them on the next frame
|
|
1158
|
-
requestAnimationFrame(() => {
|
|
1159
|
-
if (this.root.classList.contains('is-animated')) return;
|
|
1160
|
-
restoreLayoutTransition(this.transitionMuteStore);
|
|
1161
|
-
});
|
|
1162
|
-
},
|
|
1163
|
-
onPause: () => {
|
|
1164
|
-
if (this.transformAnimation) this.transformAnimation.cancel();
|
|
1165
|
-
newState.forEachRootNode(restoreNodeVisualState);
|
|
1166
|
-
this.root.classList.remove('is-animated');
|
|
1167
|
-
if (onComplete) onComplete(this);
|
|
1168
|
-
},
|
|
1169
|
-
composition: false,
|
|
1170
|
-
defaults,
|
|
1171
|
-
});
|
|
1350
|
+
tlParams.defaults = timingParams;
|
|
1351
|
+
|
|
1352
|
+
this.timeline = createTimeline(tlParams);
|
|
1353
|
+
|
|
1354
|
+
// Imediatly return the timeline if no layout changes detected
|
|
1355
|
+
if (!animated.length && !transformed.length && !swapping.length) {
|
|
1356
|
+
// Make sure to restore all CSS transition if no animation
|
|
1357
|
+
restoreLayoutTransition(this.transitionMuteStore);
|
|
1358
|
+
return this.timeline.complete();
|
|
1359
|
+
}
|
|
1172
1360
|
|
|
1173
1361
|
if (targets.length) {
|
|
1174
1362
|
|
|
@@ -1181,15 +1369,14 @@ class AutoLayout {
|
|
|
1181
1369
|
const newNode = newState.nodes.get(id);
|
|
1182
1370
|
const oldNodeState = oldNode.properties;
|
|
1183
1371
|
|
|
1184
|
-
//
|
|
1185
|
-
muteNodeTransition(newNode);
|
|
1372
|
+
// muteNodeTransition(newNode);
|
|
1186
1373
|
|
|
1187
1374
|
// Don't animate dimensions and positions of inlined elements
|
|
1188
1375
|
if (!newNode.isInlined) {
|
|
1189
1376
|
// Display grid can mess with the absolute positioning, so set it to block during transition
|
|
1190
|
-
if (oldNode.measuredDisplay === 'grid' || newNode.measuredDisplay === 'grid') $el.style.display
|
|
1191
|
-
// All children must be in position
|
|
1192
|
-
if ($el !== root || this.absoluteCoords) {
|
|
1377
|
+
if (oldNode.measuredDisplay === 'grid' || newNode.measuredDisplay === 'grid') $el.style.setProperty('display', 'block', 'important');
|
|
1378
|
+
// All children must be in position absolute or fixed
|
|
1379
|
+
if ($el !== $root || this.absoluteCoords) {
|
|
1193
1380
|
$el.style.position = this.absoluteCoords ? 'fixed' : 'absolute';
|
|
1194
1381
|
$el.style.left = '0px';
|
|
1195
1382
|
$el.style.top = '0px';
|
|
@@ -1197,7 +1384,7 @@ class AutoLayout {
|
|
|
1197
1384
|
$el.style.marginTop = '0px';
|
|
1198
1385
|
$el.style.translate = `${oldNodeState.x}px ${oldNodeState.y}px`;
|
|
1199
1386
|
}
|
|
1200
|
-
if ($el === root && newNode.measuredPosition === 'static') {
|
|
1387
|
+
if ($el === $root && newNode.measuredPosition === 'static') {
|
|
1201
1388
|
$el.style.position = 'relative';
|
|
1202
1389
|
// Cancel left / trop in case the static element had muted values now activated by potision relative
|
|
1203
1390
|
$el.style.left = '0px';
|
|
@@ -1216,9 +1403,7 @@ class AutoLayout {
|
|
|
1216
1403
|
// Restore the scroll position if the oldState differs from the current state
|
|
1217
1404
|
if (oldState.scrollX !== window.scrollX || oldState.scrollY !== window.scrollY) {
|
|
1218
1405
|
// Restoring in the next frame avoids race conditions if for example a waapi animation commit styles that affect the root height
|
|
1219
|
-
requestAnimationFrame(() =>
|
|
1220
|
-
window.scrollTo(oldState.scrollX, oldState.scrollY);
|
|
1221
|
-
});
|
|
1406
|
+
requestAnimationFrame(() => window.scrollTo(oldState.scrollX, oldState.scrollY));
|
|
1222
1407
|
}
|
|
1223
1408
|
|
|
1224
1409
|
for (let i = 0, l = animated.length; i < l; i++) {
|
|
@@ -1228,25 +1413,25 @@ class AutoLayout {
|
|
|
1228
1413
|
const newNode = newState.nodes.get(id);
|
|
1229
1414
|
const oldNodeState = oldNode.properties;
|
|
1230
1415
|
const newNodeState = newNode.properties;
|
|
1231
|
-
let
|
|
1416
|
+
let nodeHasChanged = false;
|
|
1417
|
+
/** @type {AnimationParams} */
|
|
1232
1418
|
const animatedProps = {
|
|
1233
1419
|
composition: 'none',
|
|
1234
|
-
// delay: (/** @type {HTMLElement} */$el) => newState.nodes.get($el.dataset.layoutId).delay,
|
|
1235
1420
|
};
|
|
1236
1421
|
if (!newNode.isInlined) {
|
|
1237
1422
|
if (oldNodeState.width !== newNodeState.width) {
|
|
1238
1423
|
animatedProps.width = [oldNodeState.width, newNodeState.width];
|
|
1239
|
-
|
|
1424
|
+
nodeHasChanged = true;
|
|
1240
1425
|
}
|
|
1241
1426
|
if (oldNodeState.height !== newNodeState.height) {
|
|
1242
1427
|
animatedProps.height = [oldNodeState.height, newNodeState.height];
|
|
1243
|
-
|
|
1428
|
+
nodeHasChanged = true;
|
|
1244
1429
|
}
|
|
1245
1430
|
// If the node has transforms we handle the translate animation in wappi otherwise translate and other transforms can be out of sync
|
|
1246
1431
|
// Always animate translate
|
|
1247
1432
|
if (!newNode.hasTransform) {
|
|
1248
1433
|
animatedProps.translate = [`${oldNodeState.x}px ${oldNodeState.y}px`, `${newNodeState.x}px ${newNodeState.y}px`];
|
|
1249
|
-
|
|
1434
|
+
nodeHasChanged = true;
|
|
1250
1435
|
}
|
|
1251
1436
|
}
|
|
1252
1437
|
this.properties.forEach(prop => {
|
|
@@ -1254,73 +1439,77 @@ class AutoLayout {
|
|
|
1254
1439
|
const newVal = newNodeState[prop];
|
|
1255
1440
|
if (prop !== 'transform' && oldVal !== newVal) {
|
|
1256
1441
|
animatedProps[prop] = [oldVal, newVal];
|
|
1257
|
-
|
|
1442
|
+
nodeHasChanged = true;
|
|
1258
1443
|
}
|
|
1259
1444
|
});
|
|
1260
|
-
if (
|
|
1445
|
+
if (nodeHasChanged) {
|
|
1261
1446
|
this.timeline.add($el, animatedProps, 0);
|
|
1262
1447
|
}
|
|
1263
1448
|
}
|
|
1264
1449
|
|
|
1265
1450
|
}
|
|
1266
1451
|
|
|
1267
|
-
if (
|
|
1452
|
+
if (swapping.length) {
|
|
1268
1453
|
|
|
1269
|
-
for (let i = 0, l =
|
|
1270
|
-
const $el =
|
|
1271
|
-
const oldNode = oldState.
|
|
1454
|
+
for (let i = 0, l = swapping.length; i < l; i++) {
|
|
1455
|
+
const $el = swapping[i];
|
|
1456
|
+
const oldNode = oldState.getNode($el);
|
|
1272
1457
|
if (!oldNode.isInlined) {
|
|
1273
|
-
const
|
|
1274
|
-
$el.style.width = `${
|
|
1275
|
-
$el.style.height = `${
|
|
1458
|
+
const oldNodeProps = oldNode.properties;
|
|
1459
|
+
$el.style.width = `${oldNodeProps.width}px`;
|
|
1460
|
+
$el.style.height = `${oldNodeProps.height}px`;
|
|
1276
1461
|
// Overrides user defined min and max to prevents width and height clamping
|
|
1277
1462
|
$el.style.minWidth = `auto`;
|
|
1278
1463
|
$el.style.minHeight = `auto`;
|
|
1279
1464
|
$el.style.maxWidth = `none`;
|
|
1280
1465
|
$el.style.maxHeight = `none`;
|
|
1281
|
-
$el.style.translate = `${
|
|
1466
|
+
$el.style.translate = `${oldNodeProps.x}px ${oldNodeProps.y}px`;
|
|
1282
1467
|
}
|
|
1283
1468
|
this.properties.forEach(prop => {
|
|
1284
1469
|
if (prop !== 'transform') {
|
|
1285
|
-
$el.style[prop] = `${oldState.
|
|
1470
|
+
$el.style[prop] = `${oldState.getComputedValue($el, prop)}`;
|
|
1286
1471
|
}
|
|
1287
1472
|
});
|
|
1288
1473
|
}
|
|
1289
1474
|
|
|
1290
|
-
for (let i = 0, l =
|
|
1291
|
-
const $el =
|
|
1292
|
-
const newNode = newState.
|
|
1293
|
-
const
|
|
1475
|
+
for (let i = 0, l = swapping.length; i < l; i++) {
|
|
1476
|
+
const $el = swapping[i];
|
|
1477
|
+
const newNode = newState.getNode($el);
|
|
1478
|
+
const newNodeProps = newNode.properties;
|
|
1294
1479
|
this.timeline.call(() => {
|
|
1295
1480
|
if (!newNode.isInlined) {
|
|
1296
|
-
$el.style.width = `${
|
|
1297
|
-
$el.style.height = `${
|
|
1481
|
+
$el.style.width = `${newNodeProps.width}px`;
|
|
1482
|
+
$el.style.height = `${newNodeProps.height}px`;
|
|
1298
1483
|
// Overrides user defined min and max to prevents width and height clamping
|
|
1299
1484
|
$el.style.minWidth = `auto`;
|
|
1300
1485
|
$el.style.minHeight = `auto`;
|
|
1301
1486
|
$el.style.maxWidth = `none`;
|
|
1302
1487
|
$el.style.maxHeight = `none`;
|
|
1303
|
-
$el.style.translate = `${
|
|
1488
|
+
$el.style.translate = `${newNodeProps.x}px ${newNodeProps.y}px`;
|
|
1304
1489
|
}
|
|
1305
1490
|
this.properties.forEach(prop => {
|
|
1306
1491
|
if (prop !== 'transform') {
|
|
1307
|
-
$el.style[prop] = `${newState.
|
|
1492
|
+
$el.style[prop] = `${newState.getComputedValue($el, prop)}`;
|
|
1308
1493
|
}
|
|
1309
1494
|
});
|
|
1310
1495
|
}, newNode.delay + newNode.duration / 2);
|
|
1311
1496
|
}
|
|
1312
1497
|
|
|
1313
|
-
if (
|
|
1314
|
-
const
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1498
|
+
if (animatedSwap.length) {
|
|
1499
|
+
const ease = parseEase(newState.nodes.get(animatedSwap[0].dataset.layoutId).ease);
|
|
1500
|
+
const inverseEased = t => 1 - ease(1 - t);
|
|
1501
|
+
const animatedSwapParams = /** @type {AnimationParams} */({});
|
|
1502
|
+
if (swapAtProps) {
|
|
1503
|
+
for (let prop in swapAtProps) {
|
|
1504
|
+
if (prop !== 'transform') {
|
|
1505
|
+
animatedSwapParams[prop] = [
|
|
1506
|
+
{ from: (/** @type {HTMLElement} */$el) => oldState.getComputedValue($el, prop), to: swapAtProps[prop] },
|
|
1507
|
+
{ from: swapAtProps[prop], to: (/** @type {HTMLElement} */$el) => newState.getComputedValue($el, prop), ease: inverseEased }
|
|
1508
|
+
];
|
|
1509
|
+
}
|
|
1321
1510
|
}
|
|
1322
1511
|
}
|
|
1323
|
-
this.timeline.add(
|
|
1512
|
+
this.timeline.add(animatedSwap, animatedSwapParams, 0);
|
|
1324
1513
|
}
|
|
1325
1514
|
|
|
1326
1515
|
}
|
|
@@ -1328,18 +1517,29 @@ class AutoLayout {
|
|
|
1328
1517
|
const transformedLength = transformed.length;
|
|
1329
1518
|
|
|
1330
1519
|
if (transformedLength) {
|
|
1331
|
-
// We only need to set the transform property here since translate is alread defined the targets loop
|
|
1520
|
+
// We only need to set the transform property here since translate is alread defined in the targets loop
|
|
1332
1521
|
for (let i = 0; i < transformedLength; i++) {
|
|
1333
1522
|
const $el = transformed[i];
|
|
1334
|
-
$el.style.translate = `${oldState.
|
|
1335
|
-
$el.style.transform = oldState.
|
|
1523
|
+
$el.style.translate = `${oldState.getComputedValue($el, 'x')}px ${oldState.getComputedValue($el, 'y')}px`,
|
|
1524
|
+
$el.style.transform = oldState.getComputedValue($el, 'transform');
|
|
1525
|
+
if (animatedSwap.includes($el)) {
|
|
1526
|
+
const node = newState.getNode($el);
|
|
1527
|
+
node.ease = getFunctionValue(swapAtParams.ease, $el, node.index, node.total);
|
|
1528
|
+
node.duration = getFunctionValue(swapAtParams.duration, $el, node.index, node.total);
|
|
1529
|
+
}
|
|
1336
1530
|
}
|
|
1337
1531
|
this.transformAnimation = waapi.animate(transformed, {
|
|
1338
|
-
translate: (/** @type {HTMLElement} */$el) => `${newState.
|
|
1339
|
-
transform: (/** @type {HTMLElement} */$el) =>
|
|
1532
|
+
translate: (/** @type {HTMLElement} */$el) => `${newState.getComputedValue($el, 'x')}px ${newState.getComputedValue($el, 'y')}px`,
|
|
1533
|
+
transform: (/** @type {HTMLElement} */$el) => {
|
|
1534
|
+
const newValue = newState.getComputedValue($el, 'transform');
|
|
1535
|
+
if (!animatedSwap.includes($el)) return newValue;
|
|
1536
|
+
const oldValue = oldState.getComputedValue($el, 'transform');
|
|
1537
|
+
const node = newState.getNode($el);
|
|
1538
|
+
return [oldValue, getFunctionValue(swapAtProps.transform, $el, node.index, node.total), newValue]
|
|
1539
|
+
},
|
|
1340
1540
|
autoplay: false,
|
|
1341
1541
|
persist: true,
|
|
1342
|
-
...
|
|
1542
|
+
...timingParams,
|
|
1343
1543
|
});
|
|
1344
1544
|
this.timeline.sync(this.transformAnimation, 0);
|
|
1345
1545
|
}
|
|
@@ -1350,13 +1550,12 @@ class AutoLayout {
|
|
|
1350
1550
|
/**
|
|
1351
1551
|
* @param {(layout: this) => void} callback
|
|
1352
1552
|
* @param {LayoutAnimationParams} [params]
|
|
1353
|
-
* @return {
|
|
1553
|
+
* @return {Timeline}
|
|
1354
1554
|
*/
|
|
1355
1555
|
update(callback, params = {}) {
|
|
1356
1556
|
this.record();
|
|
1357
1557
|
callback(this);
|
|
1358
|
-
this.animate(params);
|
|
1359
|
-
return this;
|
|
1558
|
+
return this.animate(params);
|
|
1360
1559
|
}
|
|
1361
1560
|
}
|
|
1362
1561
|
|