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