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