animejs 4.3.0-beta.1 → 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 +456 -266
- package/dist/bundles/anime.esm.min.js +3 -3
- package/dist/bundles/anime.umd.js +456 -266
- 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 +437 -249
- package/dist/modules/layout/layout.d.ts +44 -38
- package/dist/modules/layout/layout.js +439 -251
- 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 = [];
|
|
915
1008
|
/** @type {Array<DOMTarget>} */
|
|
916
|
-
this.
|
|
1009
|
+
this.swapping = [];
|
|
917
1010
|
/** @type {Array<DOMTarget>} */
|
|
918
|
-
this.
|
|
919
|
-
|
|
1011
|
+
this.leaving = [];
|
|
1012
|
+
/** @type {Array<DOMTarget>} */
|
|
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;
|
|
@@ -1030,26 +1175,16 @@ class AutoLayout {
|
|
|
1030
1175
|
|
|
1031
1176
|
// Recalculate postion relative to their parent for elements that have been moved
|
|
1032
1177
|
if (!oldStateNode.measuredIsRemoved && !isRemovedNow && !hasNoOldState && (parentChanged || elementChanged)) {
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
let oldOffsetY = 0;
|
|
1044
|
-
let oldCurrent = oldStateNode.parentNode;
|
|
1045
|
-
while (oldCurrent) {
|
|
1046
|
-
oldOffsetX += oldCurrent.properties.x || 0;
|
|
1047
|
-
oldOffsetY += oldCurrent.properties.y || 0;
|
|
1048
|
-
if (oldCurrent.parentNode === oldState.rootNode) break;
|
|
1049
|
-
oldCurrent = oldCurrent.parentNode;
|
|
1050
|
-
}
|
|
1051
|
-
oldStateNode.properties.x += oldOffsetX - offsetX;
|
|
1052
|
-
oldStateNode.properties.y += oldOffsetY - offsetY;
|
|
1178
|
+
const oldAbsoluteLeft = oldStateNode.properties.left;
|
|
1179
|
+
const oldAbsoluteTop = oldStateNode.properties.top;
|
|
1180
|
+
const newParent = parent || newState.rootNode;
|
|
1181
|
+
const oldParent = newParent.id ? oldState.nodes.get(newParent.id) : null;
|
|
1182
|
+
const parentLeft = oldParent ? oldParent.properties.left : newParent.properties.left;
|
|
1183
|
+
const parentTop = oldParent ? oldParent.properties.top : newParent.properties.top;
|
|
1184
|
+
const borderLeft = oldParent ? oldParent.properties.clientLeft : newParent.properties.clientLeft;
|
|
1185
|
+
const borderTop = oldParent ? oldParent.properties.clientTop : newParent.properties.clientTop;
|
|
1186
|
+
oldStateNode.properties.x = oldAbsoluteLeft - parentLeft - borderLeft;
|
|
1187
|
+
oldStateNode.properties.y = oldAbsoluteTop - parentTop - borderTop;
|
|
1053
1188
|
}
|
|
1054
1189
|
|
|
1055
1190
|
if (node.hasVisibilitySwap) {
|
|
@@ -1066,7 +1201,7 @@ class AutoLayout {
|
|
|
1066
1201
|
}
|
|
1067
1202
|
}
|
|
1068
1203
|
|
|
1069
|
-
const wasPendingRemoval =
|
|
1204
|
+
const wasPendingRemoval = pendingRemoval.has($el);
|
|
1070
1205
|
const wasVisibleBefore = oldStateNode.measuredIsVisible;
|
|
1071
1206
|
const isVisibleNow = node.measuredIsVisible;
|
|
1072
1207
|
const becomeVisible = !wasVisibleBefore && isVisibleNow && !parentNotRendered;
|
|
@@ -1074,113 +1209,156 @@ class AutoLayout {
|
|
|
1074
1209
|
const newlyRemoved = isRemovedNow && !wasRemovedBefore && !parentRemoved;
|
|
1075
1210
|
const topLevelRemoved = newlyRemoved || isRemovedNow && wasPendingRemoval && !parentRemoved;
|
|
1076
1211
|
|
|
1077
|
-
|
|
1212
|
+
node.branchAdded = parentAdded || topLevelAdded;
|
|
1213
|
+
node.branchRemoved = parentRemoved || topLevelRemoved;
|
|
1214
|
+
node.branchNotRendered = parentNotRendered || isRemovedNow;
|
|
1215
|
+
|
|
1216
|
+
if (isRemovedNow && wasVisibleBefore) {
|
|
1078
1217
|
node.$el.style.display = oldStateNode.measuredDisplay;
|
|
1079
1218
|
node.$el.style.visibility = 'visible';
|
|
1080
1219
|
cloneNodeProperties(oldStateNode, node, newState);
|
|
1081
1220
|
}
|
|
1082
1221
|
|
|
1222
|
+
// Node is leaving
|
|
1083
1223
|
if (newlyRemoved) {
|
|
1084
|
-
|
|
1085
|
-
|
|
1224
|
+
if (node.isTarget) {
|
|
1225
|
+
leaving.push($el);
|
|
1226
|
+
node.isLeaving = true;
|
|
1227
|
+
}
|
|
1228
|
+
pendingRemoval.add($el);
|
|
1086
1229
|
} else if (!isRemovedNow && wasPendingRemoval) {
|
|
1087
|
-
|
|
1230
|
+
pendingRemoval.delete($el);
|
|
1088
1231
|
}
|
|
1089
1232
|
|
|
1090
|
-
// Node is
|
|
1233
|
+
// Node is entering
|
|
1091
1234
|
if ((topLevelAdded && !parentNotRendered) || becomeVisible) {
|
|
1092
|
-
updateNodeProperties(oldStateNode,
|
|
1093
|
-
|
|
1094
|
-
|
|
1235
|
+
updateNodeProperties(oldStateNode, enterFromProps);
|
|
1236
|
+
if (node.isTarget) {
|
|
1237
|
+
entering.push($el);
|
|
1238
|
+
node.isEntering = true;
|
|
1239
|
+
}
|
|
1240
|
+
// Node is leaving
|
|
1095
1241
|
} else if (topLevelRemoved && !parentNotRendered) {
|
|
1096
|
-
updateNodeProperties(node,
|
|
1242
|
+
updateNodeProperties(node, leaveToProps);
|
|
1097
1243
|
}
|
|
1098
1244
|
|
|
1099
|
-
//
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
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);
|
|
1104
1249
|
}
|
|
1105
1250
|
|
|
1106
|
-
|
|
1107
|
-
let propertyChanged = false;
|
|
1251
|
+
targets.push($el);
|
|
1108
1252
|
|
|
1253
|
+
});
|
|
1109
1254
|
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
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;
|
|
1123
1271
|
}
|
|
1124
1272
|
|
|
1125
|
-
const
|
|
1126
|
-
|
|
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
|
+
}
|
|
1127
1299
|
|
|
1128
|
-
node
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
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;
|
|
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
|
+
}
|
|
1132
1309
|
|
|
1310
|
+
// Use a 1px tolerance to detect dimensions changes to prevent width / height animations on barelly visible elements
|
|
1133
1311
|
const sizeTolerance = 1;
|
|
1134
|
-
const widthChanged = Math.abs(
|
|
1135
|
-
const heightChanged = Math.abs(
|
|
1312
|
+
const widthChanged = Math.abs(nodeProperties.width - oldStateNodeProperties.width) > sizeTolerance;
|
|
1313
|
+
const heightChanged = Math.abs(nodeProperties.height - oldStateNodeProperties.height) > sizeTolerance;
|
|
1136
1314
|
|
|
1137
1315
|
node.sizeChanged = (widthChanged || heightChanged);
|
|
1138
1316
|
|
|
1139
|
-
|
|
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
|
+
}
|
|
1140
1332
|
|
|
1141
1333
|
if (!node.isTarget) {
|
|
1142
|
-
|
|
1143
|
-
if (
|
|
1144
|
-
|
|
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);
|
|
1145
1341
|
}
|
|
1146
1342
|
}
|
|
1343
|
+
|
|
1147
1344
|
});
|
|
1148
1345
|
|
|
1149
|
-
const
|
|
1150
|
-
|
|
1151
|
-
duration: (/** @type {HTMLElement} */$el) => newState.
|
|
1152
|
-
|
|
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,
|
|
1153
1350
|
};
|
|
1154
1351
|
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
$el.style.transform = newState.getValue($el, 'transform');
|
|
1166
|
-
}
|
|
1167
|
-
this.root.classList.remove('is-animated');
|
|
1168
|
-
if (onComplete) onComplete(this);
|
|
1169
|
-
// Avoid CSS transitions at the end of the animation by restoring them on the next frame
|
|
1170
|
-
requestAnimationFrame(() => {
|
|
1171
|
-
if (this.root.classList.contains('is-animated')) return;
|
|
1172
|
-
restoreLayoutTransition(this.transitionMuteStore);
|
|
1173
|
-
});
|
|
1174
|
-
},
|
|
1175
|
-
onPause: () => {
|
|
1176
|
-
if (this.transformAnimation) this.transformAnimation.cancel();
|
|
1177
|
-
newState.forEachRootNode(restoreNodeVisualState);
|
|
1178
|
-
this.root.classList.remove('is-animated');
|
|
1179
|
-
if (onComplete) onComplete(this);
|
|
1180
|
-
},
|
|
1181
|
-
composition: false,
|
|
1182
|
-
defaults,
|
|
1183
|
-
});
|
|
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
|
+
}
|
|
1184
1362
|
|
|
1185
1363
|
if (targets.length) {
|
|
1186
1364
|
|
|
@@ -1193,16 +1371,14 @@ class AutoLayout {
|
|
|
1193
1371
|
const newNode = newState.nodes.get(id);
|
|
1194
1372
|
const oldNodeState = oldNode.properties;
|
|
1195
1373
|
|
|
1196
|
-
//
|
|
1197
|
-
muteNodeTransition(newNode);
|
|
1374
|
+
// muteNodeTransition(newNode);
|
|
1198
1375
|
|
|
1199
1376
|
// Don't animate dimensions and positions of inlined elements
|
|
1200
1377
|
if (!newNode.isInlined) {
|
|
1201
1378
|
// Display grid can mess with the absolute positioning, so set it to block during transition
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
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) {
|
|
1206
1382
|
$el.style.position = this.absoluteCoords ? 'fixed' : 'absolute';
|
|
1207
1383
|
$el.style.left = '0px';
|
|
1208
1384
|
$el.style.top = '0px';
|
|
@@ -1210,7 +1386,7 @@ class AutoLayout {
|
|
|
1210
1386
|
$el.style.marginTop = '0px';
|
|
1211
1387
|
$el.style.translate = `${oldNodeState.x}px ${oldNodeState.y}px`;
|
|
1212
1388
|
}
|
|
1213
|
-
if ($el === root && newNode.measuredPosition === 'static') {
|
|
1389
|
+
if ($el === $root && newNode.measuredPosition === 'static') {
|
|
1214
1390
|
$el.style.position = 'relative';
|
|
1215
1391
|
// Cancel left / trop in case the static element had muted values now activated by potision relative
|
|
1216
1392
|
$el.style.left = '0px';
|
|
@@ -1229,9 +1405,7 @@ class AutoLayout {
|
|
|
1229
1405
|
// Restore the scroll position if the oldState differs from the current state
|
|
1230
1406
|
if (oldState.scrollX !== window.scrollX || oldState.scrollY !== window.scrollY) {
|
|
1231
1407
|
// Restoring in the next frame avoids race conditions if for example a waapi animation commit styles that affect the root height
|
|
1232
|
-
requestAnimationFrame(() =>
|
|
1233
|
-
window.scrollTo(oldState.scrollX, oldState.scrollY);
|
|
1234
|
-
});
|
|
1408
|
+
requestAnimationFrame(() => window.scrollTo(oldState.scrollX, oldState.scrollY));
|
|
1235
1409
|
}
|
|
1236
1410
|
|
|
1237
1411
|
for (let i = 0, l = animated.length; i < l; i++) {
|
|
@@ -1241,25 +1415,25 @@ class AutoLayout {
|
|
|
1241
1415
|
const newNode = newState.nodes.get(id);
|
|
1242
1416
|
const oldNodeState = oldNode.properties;
|
|
1243
1417
|
const newNodeState = newNode.properties;
|
|
1244
|
-
let
|
|
1418
|
+
let nodeHasChanged = false;
|
|
1419
|
+
/** @type {AnimationParams} */
|
|
1245
1420
|
const animatedProps = {
|
|
1246
1421
|
composition: 'none',
|
|
1247
|
-
// delay: (/** @type {HTMLElement} */$el) => newState.nodes.get($el.dataset.layoutId).delay,
|
|
1248
1422
|
};
|
|
1249
1423
|
if (!newNode.isInlined) {
|
|
1250
1424
|
if (oldNodeState.width !== newNodeState.width) {
|
|
1251
1425
|
animatedProps.width = [oldNodeState.width, newNodeState.width];
|
|
1252
|
-
|
|
1426
|
+
nodeHasChanged = true;
|
|
1253
1427
|
}
|
|
1254
1428
|
if (oldNodeState.height !== newNodeState.height) {
|
|
1255
1429
|
animatedProps.height = [oldNodeState.height, newNodeState.height];
|
|
1256
|
-
|
|
1430
|
+
nodeHasChanged = true;
|
|
1257
1431
|
}
|
|
1258
1432
|
// If the node has transforms we handle the translate animation in wappi otherwise translate and other transforms can be out of sync
|
|
1259
1433
|
// Always animate translate
|
|
1260
1434
|
if (!newNode.hasTransform) {
|
|
1261
1435
|
animatedProps.translate = [`${oldNodeState.x}px ${oldNodeState.y}px`, `${newNodeState.x}px ${newNodeState.y}px`];
|
|
1262
|
-
|
|
1436
|
+
nodeHasChanged = true;
|
|
1263
1437
|
}
|
|
1264
1438
|
}
|
|
1265
1439
|
this.properties.forEach(prop => {
|
|
@@ -1267,73 +1441,77 @@ class AutoLayout {
|
|
|
1267
1441
|
const newVal = newNodeState[prop];
|
|
1268
1442
|
if (prop !== 'transform' && oldVal !== newVal) {
|
|
1269
1443
|
animatedProps[prop] = [oldVal, newVal];
|
|
1270
|
-
|
|
1444
|
+
nodeHasChanged = true;
|
|
1271
1445
|
}
|
|
1272
1446
|
});
|
|
1273
|
-
if (
|
|
1447
|
+
if (nodeHasChanged) {
|
|
1274
1448
|
this.timeline.add($el, animatedProps, 0);
|
|
1275
1449
|
}
|
|
1276
1450
|
}
|
|
1277
1451
|
|
|
1278
1452
|
}
|
|
1279
1453
|
|
|
1280
|
-
if (
|
|
1454
|
+
if (swapping.length) {
|
|
1281
1455
|
|
|
1282
|
-
for (let i = 0, l =
|
|
1283
|
-
const $el =
|
|
1284
|
-
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);
|
|
1285
1459
|
if (!oldNode.isInlined) {
|
|
1286
|
-
const
|
|
1287
|
-
$el.style.width = `${
|
|
1288
|
-
$el.style.height = `${
|
|
1460
|
+
const oldNodeProps = oldNode.properties;
|
|
1461
|
+
$el.style.width = `${oldNodeProps.width}px`;
|
|
1462
|
+
$el.style.height = `${oldNodeProps.height}px`;
|
|
1289
1463
|
// Overrides user defined min and max to prevents width and height clamping
|
|
1290
1464
|
$el.style.minWidth = `auto`;
|
|
1291
1465
|
$el.style.minHeight = `auto`;
|
|
1292
1466
|
$el.style.maxWidth = `none`;
|
|
1293
1467
|
$el.style.maxHeight = `none`;
|
|
1294
|
-
$el.style.translate = `${
|
|
1468
|
+
$el.style.translate = `${oldNodeProps.x}px ${oldNodeProps.y}px`;
|
|
1295
1469
|
}
|
|
1296
1470
|
this.properties.forEach(prop => {
|
|
1297
1471
|
if (prop !== 'transform') {
|
|
1298
|
-
$el.style[prop] = `${oldState.
|
|
1472
|
+
$el.style[prop] = `${oldState.getComputedValue($el, prop)}`;
|
|
1299
1473
|
}
|
|
1300
1474
|
});
|
|
1301
1475
|
}
|
|
1302
1476
|
|
|
1303
|
-
for (let i = 0, l =
|
|
1304
|
-
const $el =
|
|
1305
|
-
const newNode = newState.
|
|
1306
|
-
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;
|
|
1307
1481
|
this.timeline.call(() => {
|
|
1308
1482
|
if (!newNode.isInlined) {
|
|
1309
|
-
$el.style.width = `${
|
|
1310
|
-
$el.style.height = `${
|
|
1483
|
+
$el.style.width = `${newNodeProps.width}px`;
|
|
1484
|
+
$el.style.height = `${newNodeProps.height}px`;
|
|
1311
1485
|
// Overrides user defined min and max to prevents width and height clamping
|
|
1312
1486
|
$el.style.minWidth = `auto`;
|
|
1313
1487
|
$el.style.minHeight = `auto`;
|
|
1314
1488
|
$el.style.maxWidth = `none`;
|
|
1315
1489
|
$el.style.maxHeight = `none`;
|
|
1316
|
-
$el.style.translate = `${
|
|
1490
|
+
$el.style.translate = `${newNodeProps.x}px ${newNodeProps.y}px`;
|
|
1317
1491
|
}
|
|
1318
1492
|
this.properties.forEach(prop => {
|
|
1319
1493
|
if (prop !== 'transform') {
|
|
1320
|
-
$el.style[prop] = `${newState.
|
|
1494
|
+
$el.style[prop] = `${newState.getComputedValue($el, prop)}`;
|
|
1321
1495
|
}
|
|
1322
1496
|
});
|
|
1323
1497
|
}, newNode.delay + newNode.duration / 2);
|
|
1324
1498
|
}
|
|
1325
1499
|
|
|
1326
|
-
if (
|
|
1327
|
-
const
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
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
|
+
}
|
|
1334
1512
|
}
|
|
1335
1513
|
}
|
|
1336
|
-
this.timeline.add(
|
|
1514
|
+
this.timeline.add(animatedSwap, animatedSwapParams, 0);
|
|
1337
1515
|
}
|
|
1338
1516
|
|
|
1339
1517
|
}
|
|
@@ -1341,18 +1519,29 @@ class AutoLayout {
|
|
|
1341
1519
|
const transformedLength = transformed.length;
|
|
1342
1520
|
|
|
1343
1521
|
if (transformedLength) {
|
|
1344
|
-
// 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
|
|
1345
1523
|
for (let i = 0; i < transformedLength; i++) {
|
|
1346
1524
|
const $el = transformed[i];
|
|
1347
|
-
$el.style.translate = `${oldState.
|
|
1348
|
-
$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
|
+
}
|
|
1349
1532
|
}
|
|
1350
1533
|
this.transformAnimation = waapi.waapi.animate(transformed, {
|
|
1351
|
-
translate: (/** @type {HTMLElement} */$el) => `${newState.
|
|
1352
|
-
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
|
+
},
|
|
1353
1542
|
autoplay: false,
|
|
1354
1543
|
persist: true,
|
|
1355
|
-
...
|
|
1544
|
+
...timingParams,
|
|
1356
1545
|
});
|
|
1357
1546
|
this.timeline.sync(this.transformAnimation, 0);
|
|
1358
1547
|
}
|
|
@@ -1363,13 +1552,12 @@ class AutoLayout {
|
|
|
1363
1552
|
/**
|
|
1364
1553
|
* @param {(layout: this) => void} callback
|
|
1365
1554
|
* @param {LayoutAnimationParams} [params]
|
|
1366
|
-
* @return {
|
|
1555
|
+
* @return {Timeline}
|
|
1367
1556
|
*/
|
|
1368
1557
|
update(callback, params = {}) {
|
|
1369
1558
|
this.record();
|
|
1370
1559
|
callback(this);
|
|
1371
|
-
this.animate(params);
|
|
1372
|
-
return this;
|
|
1560
|
+
return this.animate(params);
|
|
1373
1561
|
}
|
|
1374
1562
|
}
|
|
1375
1563
|
|