motion 12.7.4 → 12.7.5-alpha.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 +1 -1
- package/dist/cjs/debug.js +22 -14
- package/dist/cjs/index.js +4113 -3624
- package/dist/cjs/mini.js +403 -324
- package/dist/cjs/react-client.js +3151 -3245
- package/dist/cjs/react-m.js +169 -166
- package/dist/cjs/react-mini.js +330 -251
- package/dist/es/framer-motion/dist/es/animation/animate/sequence.mjs +1 -1
- package/dist/es/framer-motion/dist/es/animation/animators/waapi/animate-elements.mjs +81 -9
- package/dist/es/framer-motion/dist/es/animation/interfaces/motion-value.mjs +11 -30
- package/dist/es/framer-motion/dist/es/animation/interfaces/visual-element-target.mjs +1 -1
- package/dist/es/framer-motion/dist/es/animation/optimized-appear/store-id.mjs +1 -1
- package/dist/es/framer-motion/dist/es/animation/sequence/create.mjs +3 -3
- package/dist/es/framer-motion/dist/es/animation/sequence/utils/edit.mjs +2 -2
- package/dist/es/framer-motion/dist/es/animation/utils/default-transitions.mjs +1 -1
- package/dist/es/framer-motion/dist/es/animation/utils/stagger.mjs +1 -1
- package/dist/es/framer-motion/dist/es/components/Reorder/utils/check-reorder.mjs +1 -1
- package/dist/es/framer-motion/dist/es/gestures/drag/VisualElementDragControls.mjs +2 -2
- package/dist/es/framer-motion/dist/es/gestures/drag/utils/constraints.mjs +2 -2
- package/dist/es/framer-motion/dist/es/gestures/focus.mjs +1 -1
- package/dist/es/framer-motion/dist/es/gestures/pan/PanSession.mjs +1 -1
- package/dist/es/framer-motion/dist/es/motion/utils/is-forced-motion-value.mjs +1 -1
- package/dist/es/framer-motion/dist/es/projection/animation/mix-values.mjs +3 -3
- package/dist/es/framer-motion/dist/es/projection/geometry/delta-apply.mjs +1 -1
- package/dist/es/framer-motion/dist/es/projection/geometry/delta-calc.mjs +1 -1
- package/dist/es/framer-motion/dist/es/projection/geometry/delta-remove.mjs +2 -2
- package/dist/es/framer-motion/dist/es/projection/node/create-projection-node.mjs +3 -5
- package/dist/es/framer-motion/dist/es/projection/styles/scale-border-radius.mjs +1 -1
- package/dist/es/framer-motion/dist/es/projection/styles/scale-box-shadow.mjs +2 -2
- package/dist/es/framer-motion/dist/es/projection/styles/scale-correction.mjs +1 -1
- package/dist/es/framer-motion/dist/es/render/VisualElement.mjs +7 -7
- package/dist/es/framer-motion/dist/es/render/dom/DOMVisualElement.mjs +1 -1
- package/dist/es/framer-motion/dist/es/render/dom/scroll/attach-animation.mjs +17 -0
- package/dist/es/framer-motion/dist/es/render/dom/scroll/attach-function.mjs +23 -0
- package/dist/es/framer-motion/dist/es/render/dom/scroll/index.mjs +6 -82
- package/dist/es/framer-motion/dist/es/render/dom/scroll/offsets/index.mjs +3 -3
- package/dist/es/framer-motion/dist/es/render/dom/scroll/utils/get-timeline.mjs +29 -0
- package/dist/es/framer-motion/dist/es/render/html/HTMLVisualElement.mjs +3 -3
- package/dist/es/framer-motion/dist/es/render/html/utils/build-styles.mjs +4 -4
- package/dist/es/framer-motion/dist/es/render/html/utils/build-transform.mjs +3 -3
- package/dist/es/framer-motion/dist/es/render/svg/SVGVisualElement.mjs +2 -2
- package/dist/es/framer-motion/dist/es/render/svg/config-motion.mjs +1 -1
- package/dist/es/framer-motion/dist/es/render/svg/utils/path.mjs +1 -1
- package/dist/es/framer-motion/dist/es/render/svg/utils/scrape-motion-values.mjs +1 -1
- package/dist/es/framer-motion/dist/es/render/svg/utils/transform-origin.mjs +1 -1
- package/dist/es/framer-motion/dist/es/render/utils/motion-values.mjs +1 -1
- package/dist/es/framer-motion/dist/es/utils/delay.mjs +1 -1
- package/dist/es/framer-motion/dist/es/utils/transform.mjs +1 -1
- package/dist/es/framer-motion/dist/es/utils/use-cycle.mjs +1 -1
- package/dist/es/framer-motion/dist/es/utils/use-instant-transition.mjs +4 -4
- package/dist/es/framer-motion/dist/es/value/use-spring.mjs +2 -2
- package/dist/es/framer-motion/dist/es/value/use-will-change/get-will-change-name.mjs +2 -2
- package/dist/es/motion/lib/index.mjs +109 -26
- package/dist/es/motion/lib/react.mjs +108 -32
- package/dist/es/motion-dom/dist/es/animation/AsyncMotionValueAnimation.mjs +179 -0
- package/dist/es/motion-dom/dist/es/animation/GroupAnimation.mjs +6 -15
- package/dist/es/{framer-motion/dist/es/animation/animators/MainThreadAnimation.mjs → motion-dom/dist/es/animation/JSAnimation.mjs} +108 -156
- package/dist/es/motion-dom/dist/es/animation/NativeAnimation.mjs +64 -67
- package/dist/es/motion-dom/dist/es/animation/NativeAnimationExtended.mjs +65 -0
- package/dist/es/motion-dom/dist/es/animation/NativeAnimationWrapper.mjs +14 -0
- package/dist/es/{framer-motion/dist/es/animation/animators → motion-dom/dist/es/animation}/drivers/driver-frameloop.mjs +2 -2
- package/dist/es/{framer-motion → motion-dom}/dist/es/animation/generators/keyframes.mjs +5 -5
- package/dist/es/{framer-motion → motion-dom}/dist/es/animation/generators/spring/find.mjs +1 -1
- package/dist/es/{framer-motion → motion-dom}/dist/es/animation/generators/spring/index.mjs +5 -6
- package/dist/es/{framer-motion/dist/es/render/dom → motion-dom/dist/es/animation/keyframes}/DOMKeyframesResolver.mjs +9 -8
- package/dist/es/{framer-motion/dist/es/render/utils → motion-dom/dist/es/animation/keyframes}/KeyframesResolver.mjs +28 -35
- package/dist/es/motion-dom/dist/es/animation/keyframes/get-final.mjs +3 -4
- package/dist/es/{framer-motion/dist/es/utils → motion-dom/dist/es/animation/keyframes}/offsets/fill.mjs +2 -2
- package/dist/es/motion-dom/dist/es/animation/keyframes/utils/apply-px-defaults.mjs +11 -0
- package/dist/es/motion-dom/dist/es/animation/keyframes/utils/fill-wildcards.mjs +7 -0
- package/dist/es/{framer-motion/dist/es/animation → motion-dom/dist/es/animation/keyframes}/utils/is-none.mjs +1 -1
- package/dist/es/{framer-motion/dist/es/render/html → motion-dom/dist/es/animation/keyframes}/utils/make-none-animatable.mjs +1 -1
- package/dist/es/{framer-motion/dist/es/render/dom → motion-dom/dist/es/animation/keyframes}/utils/unit-conversion.mjs +2 -2
- package/dist/es/motion-dom/dist/es/animation/utils/WithPromise.mjs +28 -0
- package/dist/es/motion-dom/dist/es/animation/utils/active-animations.mjs +9 -0
- package/dist/es/{framer-motion/dist/es/animation/animators → motion-dom/dist/es/animation}/utils/can-animate.mjs +3 -3
- package/dist/es/{framer-motion/dist/es/render/dom → motion-dom/dist/es/animation}/utils/css-variables-conversion.mjs +2 -2
- package/dist/es/motion-dom/dist/es/animation/utils/replace-transition-type.mjs +18 -0
- package/dist/es/motion-dom/dist/es/animation/waapi/easing/is-supported.mjs +1 -1
- package/dist/es/motion-dom/dist/es/animation/waapi/easing/map-easing.mjs +5 -3
- package/dist/es/motion-dom/dist/es/animation/waapi/start-waapi-animation.mjs +6 -4
- package/dist/es/motion-dom/dist/es/animation/waapi/supports/waapi.mjs +39 -0
- package/dist/es/motion-dom/dist/es/animation/waapi/utils/apply-generator.mjs +2 -1
- package/dist/es/motion-dom/dist/es/animation/waapi/utils/unsupported-easing.mjs +20 -0
- package/dist/es/motion-dom/dist/es/frameloop/batcher.mjs +2 -1
- package/dist/es/motion-dom/dist/es/frameloop/order.mjs +1 -0
- package/dist/es/motion-dom/dist/es/render/dom/is-css-var.mjs +3 -0
- package/dist/es/motion-dom/dist/es/render/dom/style-computed.mjs +10 -0
- package/dist/es/motion-dom/dist/es/render/dom/style-set.mjs +9 -0
- package/dist/es/{framer-motion/dist/es/render/html → motion-dom/dist/es/render}/utils/keys-transform.mjs +1 -1
- package/dist/es/{framer-motion/dist/es/render/dom → motion-dom/dist/es}/scroll/observe.mjs +1 -1
- package/dist/es/motion-dom/dist/es/stats/index.mjs +2 -0
- package/dist/es/{framer-motion → motion-dom}/dist/es/utils/interpolate.mjs +4 -3
- package/dist/es/{framer-motion → motion-dom}/dist/es/utils/mix/color.mjs +3 -3
- package/dist/es/{framer-motion → motion-dom}/dist/es/utils/mix/complex.mjs +5 -5
- package/dist/es/motion-dom/dist/es/value/index.mjs +3 -1
- package/dist/es/{framer-motion → motion-dom}/dist/es/value/types/color/rgba.mjs +2 -2
- package/dist/es/{framer-motion/dist/es/render/dom/value-types → motion-dom/dist/es/value/types}/dimensions.mjs +3 -3
- package/dist/es/{framer-motion/dist/es/render/dom/value-types/type-int.mjs → motion-dom/dist/es/value/types/int.mjs} +1 -1
- package/dist/es/{framer-motion/dist/es/render/dom/value-types → motion-dom/dist/es/value/types/maps}/defaults.mjs +2 -2
- package/dist/es/{framer-motion/dist/es/render/dom/value-types/number-browser.mjs → motion-dom/dist/es/value/types/maps/number.mjs} +13 -3
- package/dist/es/{framer-motion/dist/es/render/dom/value-types → motion-dom/dist/es/value/types/maps}/transform.mjs +2 -2
- package/dist/es/{framer-motion → motion-dom}/dist/es/value/types/numbers/index.mjs +1 -1
- package/dist/es/{framer-motion → motion-dom}/dist/es/value/types/numbers/units.mjs +3 -2
- package/dist/es/{framer-motion/dist/es/render/dom/value-types → motion-dom/dist/es/value/types/utils}/animatable-none.mjs +4 -4
- package/dist/es/{framer-motion/dist/es/render/dom/value-types → motion-dom/dist/es/value/types/utils}/find.mjs +4 -4
- package/dist/es/motion-dom/dist/es/view/index.mjs +64 -0
- package/dist/es/motion-dom/dist/es/view/queue.mjs +52 -0
- package/dist/es/motion-dom/dist/es/view/start.mjs +155 -0
- package/dist/es/motion-dom/dist/es/view/utils/choose-layer-type.mjs +11 -0
- package/dist/es/motion-dom/dist/es/view/utils/css.mjs +32 -0
- package/dist/es/motion-dom/dist/es/view/utils/get-layer-name.mjs +8 -0
- package/dist/es/motion-dom/dist/es/view/utils/get-view-animations.mjs +12 -0
- package/dist/es/motion-dom/dist/es/view/utils/has-target.mjs +5 -0
- package/dist/es/{framer-motion → motion-utils}/dist/es/easing/cubic-bezier.mjs +1 -1
- package/dist/es/{framer-motion → motion-utils}/dist/es/easing/steps.mjs +1 -1
- package/dist/es/{framer-motion → motion-utils}/dist/es/easing/utils/get-easing-for-segment.mjs +1 -1
- package/dist/es/{framer-motion → motion-utils}/dist/es/easing/utils/map.mjs +7 -4
- package/dist/es/motion-utils/dist/es/global-config.mjs +1 -4
- package/dist/es/motion-utils/dist/es/warn-once.mjs +4 -1
- package/dist/motion.dev.js +4108 -3619
- package/dist/motion.js +1 -1
- package/package.json +3 -3
- package/dist/es/framer-motion/dist/es/animation/animators/AcceleratedAnimation.mjs +0 -324
- package/dist/es/framer-motion/dist/es/animation/animators/BaseAnimation.mjs +0 -120
- package/dist/es/framer-motion/dist/es/animation/animators/waapi/utils/supports-waapi.mjs +0 -5
- package/dist/es/framer-motion/dist/es/render/dom/value-types/number.mjs +0 -18
- package/dist/es/framer-motion/dist/es/utils/use-instant-transition-state.mjs +0 -5
- package/dist/es/motion-dom/dist/es/animation/keyframes/hydrate.mjs +0 -26
- package/dist/es/motion-dom/dist/es/animation/waapi/utils/attach-timeline.mjs +0 -6
- package/dist/es/motion-dom/dist/es/render/dom/style.mjs +0 -15
- /package/dist/es/{framer-motion → motion-dom}/dist/es/animation/generators/inertia.mjs +0 -0
- /package/dist/es/{framer-motion → motion-dom}/dist/es/animation/generators/spring/defaults.mjs +0 -0
- /package/dist/es/{framer-motion → motion-dom}/dist/es/animation/generators/utils/velocity.mjs +0 -0
- /package/dist/es/{framer-motion/dist/es/utils → motion-dom/dist/es/animation/keyframes}/offsets/default.mjs +0 -0
- /package/dist/es/{framer-motion/dist/es/utils → motion-dom/dist/es/animation/keyframes}/offsets/time.mjs +0 -0
- /package/dist/es/{framer-motion → motion-dom}/dist/es/animation/utils/is-animatable.mjs +0 -0
- /package/dist/es/{framer-motion/dist/es/render/dom → motion-dom/dist/es/animation}/utils/is-css-variable.mjs +0 -0
- /package/dist/es/{framer-motion/dist/es/animation/animators → motion-dom/dist/es/animation/waapi}/utils/accelerated-values.mjs +0 -0
- /package/dist/es/{framer-motion/dist/es/render/html/utils → motion-dom/dist/es/render/dom}/parse-transform.mjs +0 -0
- /package/dist/es/{framer-motion/dist/es/render/html → motion-dom/dist/es/render}/utils/keys-position.mjs +0 -0
- /package/dist/es/{framer-motion → motion-dom}/dist/es/utils/mix/immediate.mjs +0 -0
- /package/dist/es/{framer-motion → motion-dom}/dist/es/utils/mix/index.mjs +0 -0
- /package/dist/es/{framer-motion → motion-dom}/dist/es/utils/mix/number.mjs +0 -0
- /package/dist/es/{framer-motion → motion-dom}/dist/es/utils/mix/visibility.mjs +0 -0
- /package/dist/es/{framer-motion/dist/es/render/dom/value-types/type-auto.mjs → motion-dom/dist/es/value/types/auto.mjs} +0 -0
- /package/dist/es/{framer-motion → motion-dom}/dist/es/value/types/color/hex.mjs +0 -0
- /package/dist/es/{framer-motion/dist/es/utils → motion-dom/dist/es/value/types/color}/hsla-to-rgba.mjs +0 -0
- /package/dist/es/{framer-motion → motion-dom}/dist/es/value/types/color/hsla.mjs +0 -0
- /package/dist/es/{framer-motion → motion-dom}/dist/es/value/types/color/index.mjs +0 -0
- /package/dist/es/{framer-motion → motion-dom}/dist/es/value/types/color/utils.mjs +0 -0
- /package/dist/es/{framer-motion → motion-dom}/dist/es/value/types/complex/filter.mjs +0 -0
- /package/dist/es/{framer-motion → motion-dom}/dist/es/value/types/complex/index.mjs +0 -0
- /package/dist/es/{framer-motion/dist/es/render/dom/value-types → motion-dom/dist/es/value/types}/test.mjs +0 -0
- /package/dist/es/{framer-motion → motion-dom}/dist/es/value/types/utils/color-regex.mjs +0 -0
- /package/dist/es/{framer-motion → motion-dom}/dist/es/value/types/utils/float-regex.mjs +0 -0
- /package/dist/es/{framer-motion/dist/es/render/dom/value-types → motion-dom/dist/es/value/types/utils}/get-as-type.mjs +0 -0
- /package/dist/es/{framer-motion → motion-dom}/dist/es/value/types/utils/is-nullish.mjs +0 -0
- /package/dist/es/{framer-motion → motion-dom}/dist/es/value/types/utils/sanitize.mjs +0 -0
- /package/dist/es/{framer-motion → motion-dom}/dist/es/value/types/utils/single-color-regex.mjs +0 -0
- /package/dist/es/{framer-motion/dist/es/utils → motion-utils/dist/es}/clamp.mjs +0 -0
- /package/dist/es/{framer-motion → motion-utils}/dist/es/easing/anticipate.mjs +0 -0
- /package/dist/es/{framer-motion → motion-utils}/dist/es/easing/back.mjs +0 -0
- /package/dist/es/{framer-motion → motion-utils}/dist/es/easing/circ.mjs +0 -0
- /package/dist/es/{framer-motion → motion-utils}/dist/es/easing/ease.mjs +0 -0
- /package/dist/es/{framer-motion → motion-utils}/dist/es/easing/modifiers/mirror.mjs +0 -0
- /package/dist/es/{framer-motion → motion-utils}/dist/es/easing/modifiers/reverse.mjs +0 -0
- /package/dist/es/{motion-dom/dist/es → motion-utils/dist/es/easing}/utils/is-bezier-definition.mjs +0 -0
- /package/dist/es/{framer-motion → motion-utils}/dist/es/easing/utils/is-easing-array.mjs +0 -0
- /package/dist/es/{framer-motion/dist/es/utils → motion-utils/dist/es}/is-numerical-string.mjs +0 -0
- /package/dist/es/{framer-motion/dist/es/utils → motion-utils/dist/es}/is-zero-value-string.mjs +0 -0
- /package/dist/es/{framer-motion/dist/es/utils → motion-utils/dist/es}/pipe.mjs +0 -0
- /package/dist/es/{framer-motion/dist/es/utils → motion-utils/dist/es}/wrap.mjs +0 -0
package/dist/cjs/react-mini.js
CHANGED
|
@@ -56,187 +56,71 @@ const secondsToMilliseconds = (seconds) => seconds * 1000;
|
|
|
56
56
|
/*#__NO_SIDE_EFFECTS__*/
|
|
57
57
|
const millisecondsToSeconds = (milliseconds) => milliseconds / 1000;
|
|
58
58
|
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
class GroupAnimation {
|
|
62
|
-
constructor(animations) {
|
|
63
|
-
// Bound to accomodate common `return animation.stop` pattern
|
|
64
|
-
this.stop = () => this.runAll("stop");
|
|
65
|
-
this.animations = animations.filter(Boolean);
|
|
66
|
-
}
|
|
67
|
-
get finished() {
|
|
68
|
-
return Promise.all(this.animations.map((animation) => animation.finished));
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* TODO: Filter out cancelled or stopped animations before returning
|
|
72
|
-
*/
|
|
73
|
-
getAll(propName) {
|
|
74
|
-
return this.animations[0][propName];
|
|
75
|
-
}
|
|
76
|
-
setAll(propName, newValue) {
|
|
77
|
-
for (let i = 0; i < this.animations.length; i++) {
|
|
78
|
-
this.animations[i][propName] = newValue;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
attachTimeline(timeline, fallback) {
|
|
82
|
-
const subscriptions = this.animations.map((animation) => {
|
|
83
|
-
if (supportsScrollTimeline() && animation.attachTimeline) {
|
|
84
|
-
return animation.attachTimeline(timeline);
|
|
85
|
-
}
|
|
86
|
-
else if (typeof fallback === "function") {
|
|
87
|
-
return fallback(animation);
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
return () => {
|
|
91
|
-
subscriptions.forEach((cancel, i) => {
|
|
92
|
-
cancel && cancel();
|
|
93
|
-
this.animations[i].stop();
|
|
94
|
-
});
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
get time() {
|
|
98
|
-
return this.getAll("time");
|
|
99
|
-
}
|
|
100
|
-
set time(time) {
|
|
101
|
-
this.setAll("time", time);
|
|
102
|
-
}
|
|
103
|
-
get speed() {
|
|
104
|
-
return this.getAll("speed");
|
|
105
|
-
}
|
|
106
|
-
set speed(speed) {
|
|
107
|
-
this.setAll("speed", speed);
|
|
108
|
-
}
|
|
109
|
-
get startTime() {
|
|
110
|
-
return this.getAll("startTime");
|
|
111
|
-
}
|
|
112
|
-
get duration() {
|
|
113
|
-
let max = 0;
|
|
114
|
-
for (let i = 0; i < this.animations.length; i++) {
|
|
115
|
-
max = Math.max(max, this.animations[i].duration);
|
|
116
|
-
}
|
|
117
|
-
return max;
|
|
118
|
-
}
|
|
119
|
-
runAll(methodName) {
|
|
120
|
-
this.animations.forEach((controls) => controls[methodName]());
|
|
121
|
-
}
|
|
122
|
-
flatten() {
|
|
123
|
-
this.runAll("flatten");
|
|
124
|
-
}
|
|
125
|
-
play() {
|
|
126
|
-
this.runAll("play");
|
|
127
|
-
}
|
|
128
|
-
pause() {
|
|
129
|
-
this.runAll("pause");
|
|
130
|
-
}
|
|
131
|
-
cancel() {
|
|
132
|
-
this.runAll("cancel");
|
|
133
|
-
}
|
|
134
|
-
complete() {
|
|
135
|
-
this.runAll("complete");
|
|
136
|
-
}
|
|
137
|
-
}
|
|
59
|
+
const isBezierDefinition = (easing) => Array.isArray(easing) && typeof easing[0] === "number";
|
|
138
60
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
61
|
+
const generateLinearEasing = (easing, duration, // as milliseconds
|
|
62
|
+
resolution = 10 // as milliseconds
|
|
63
|
+
) => {
|
|
64
|
+
let points = "";
|
|
65
|
+
const numPoints = Math.max(Math.round(duration / resolution), 2);
|
|
66
|
+
for (let i = 0; i < numPoints; i++) {
|
|
67
|
+
points += easing(i / (numPoints - 1)) + ", ";
|
|
142
68
|
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const isCSSVar = (name) => name.startsWith("--");
|
|
146
|
-
const style = {
|
|
147
|
-
set: (element, name, value) => {
|
|
148
|
-
isCSSVar(name)
|
|
149
|
-
? element.style.setProperty(name, value)
|
|
150
|
-
: (element.style[name] = value);
|
|
151
|
-
},
|
|
152
|
-
get: (element, name) => {
|
|
153
|
-
return isCSSVar(name)
|
|
154
|
-
? element.style.getPropertyValue(name)
|
|
155
|
-
: element.style[name];
|
|
156
|
-
},
|
|
69
|
+
return `linear(${points.substring(0, points.length - 2)})`;
|
|
157
70
|
};
|
|
158
71
|
|
|
159
72
|
const isNotNull = (value) => value !== null;
|
|
160
|
-
function getFinalKeyframe(keyframes, { repeat, repeatType = "loop" }, finalKeyframe) {
|
|
73
|
+
function getFinalKeyframe(keyframes, { repeat, repeatType = "loop" }, finalKeyframe, speed = 1) {
|
|
161
74
|
const resolvedKeyframes = keyframes.filter(isNotNull);
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
: resolvedKeyframes.length - 1;
|
|
75
|
+
const useFirstKeyframe = speed < 0 || (repeat && repeatType !== "loop" && repeat % 2 === 1);
|
|
76
|
+
const index = useFirstKeyframe ? 0 : resolvedKeyframes.length - 1;
|
|
165
77
|
return !index || finalKeyframe === undefined
|
|
166
78
|
? resolvedKeyframes[index]
|
|
167
79
|
: finalKeyframe;
|
|
168
80
|
}
|
|
169
81
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
82
|
+
class WithPromise {
|
|
83
|
+
constructor() {
|
|
84
|
+
this.count = 0;
|
|
85
|
+
this.updateFinished();
|
|
173
86
|
}
|
|
174
|
-
|
|
175
|
-
return
|
|
87
|
+
get finished() {
|
|
88
|
+
return this._finished;
|
|
176
89
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
"borderWidth",
|
|
183
|
-
"borderTopWidth",
|
|
184
|
-
"borderRightWidth",
|
|
185
|
-
"borderBottomWidth",
|
|
186
|
-
"borderLeftWidth",
|
|
187
|
-
"borderRadius",
|
|
188
|
-
"radius",
|
|
189
|
-
"borderTopLeftRadius",
|
|
190
|
-
"borderTopRightRadius",
|
|
191
|
-
"borderBottomRightRadius",
|
|
192
|
-
"borderBottomLeftRadius",
|
|
193
|
-
// Positioning props
|
|
194
|
-
"width",
|
|
195
|
-
"maxWidth",
|
|
196
|
-
"height",
|
|
197
|
-
"maxHeight",
|
|
198
|
-
"top",
|
|
199
|
-
"right",
|
|
200
|
-
"bottom",
|
|
201
|
-
"left",
|
|
202
|
-
// Spacing props
|
|
203
|
-
"padding",
|
|
204
|
-
"paddingTop",
|
|
205
|
-
"paddingRight",
|
|
206
|
-
"paddingBottom",
|
|
207
|
-
"paddingLeft",
|
|
208
|
-
"margin",
|
|
209
|
-
"marginTop",
|
|
210
|
-
"marginRight",
|
|
211
|
-
"marginBottom",
|
|
212
|
-
"marginLeft",
|
|
213
|
-
// Misc
|
|
214
|
-
"backgroundPositionX",
|
|
215
|
-
"backgroundPositionY",
|
|
216
|
-
]);
|
|
217
|
-
|
|
218
|
-
function hydrateKeyframes(element, name, keyframes, pseudoElement) {
|
|
219
|
-
if (!Array.isArray(keyframes)) {
|
|
220
|
-
keyframes = [keyframes];
|
|
90
|
+
updateFinished() {
|
|
91
|
+
this.count++;
|
|
92
|
+
this._finished = new Promise((resolve) => {
|
|
93
|
+
this.resolve = resolve;
|
|
94
|
+
});
|
|
221
95
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
keyframes[i] =
|
|
225
|
-
i === 0 && !pseudoElement
|
|
226
|
-
? style.get(element, name)
|
|
227
|
-
: keyframes[i - 1];
|
|
228
|
-
}
|
|
229
|
-
if (typeof keyframes[i] === "number" && pxValues.has(name)) {
|
|
230
|
-
keyframes[i] = keyframes[i] + "px";
|
|
231
|
-
}
|
|
96
|
+
notifyFinished() {
|
|
97
|
+
this.resolve();
|
|
232
98
|
}
|
|
233
|
-
|
|
234
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Allows the animation to be awaited.
|
|
101
|
+
*
|
|
102
|
+
* @deprecated Use `finished` instead.
|
|
103
|
+
*/
|
|
104
|
+
then(onResolve, onReject) {
|
|
105
|
+
return this.finished.then(onResolve, onReject);
|
|
235
106
|
}
|
|
236
|
-
return keyframes;
|
|
237
107
|
}
|
|
238
108
|
|
|
239
|
-
|
|
109
|
+
function fillWildcards(keyframes) {
|
|
110
|
+
for (let i = 1; i < keyframes.length; i++) {
|
|
111
|
+
keyframes[i] ?? (keyframes[i] = keyframes[i - 1]);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const isCSSVar = (name) => name.startsWith("--");
|
|
116
|
+
|
|
117
|
+
function setStyle(element, name, value) {
|
|
118
|
+
isCSSVar(name)
|
|
119
|
+
? element.style.setProperty(name, value)
|
|
120
|
+
: (element.style[name] = value);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const supportsScrollTimeline = /* @__PURE__ */ memo(() => window.ScrollTimeline !== undefined);
|
|
240
124
|
|
|
241
125
|
/**
|
|
242
126
|
* Add the ability for test suites to manually set support flags
|
|
@@ -261,17 +145,6 @@ const supportsLinearEasing = /*@__PURE__*/ memoSupports(() => {
|
|
|
261
145
|
return true;
|
|
262
146
|
}, "linearEasing");
|
|
263
147
|
|
|
264
|
-
const generateLinearEasing = (easing, duration, // as milliseconds
|
|
265
|
-
resolution = 10 // as milliseconds
|
|
266
|
-
) => {
|
|
267
|
-
let points = "";
|
|
268
|
-
const numPoints = Math.max(Math.round(duration / resolution), 2);
|
|
269
|
-
for (let i = 0; i < numPoints; i++) {
|
|
270
|
-
points += easing(i / (numPoints - 1)) + ", ";
|
|
271
|
-
}
|
|
272
|
-
return `linear(${points.substring(0, points.length - 2)})`;
|
|
273
|
-
};
|
|
274
|
-
|
|
275
148
|
const cubicBezierAsString = ([a, b, c, d]) => `cubic-bezier(${a}, ${b}, ${c}, ${d})`;
|
|
276
149
|
|
|
277
150
|
const supportedWaapiEasing = {
|
|
@@ -290,8 +163,10 @@ function mapEasingToNativeEasing(easing, duration) {
|
|
|
290
163
|
if (!easing) {
|
|
291
164
|
return undefined;
|
|
292
165
|
}
|
|
293
|
-
else if (typeof easing === "function"
|
|
294
|
-
return
|
|
166
|
+
else if (typeof easing === "function") {
|
|
167
|
+
return supportsLinearEasing()
|
|
168
|
+
? generateLinearEasing(easing, duration)
|
|
169
|
+
: "ease-out";
|
|
295
170
|
}
|
|
296
171
|
else if (isBezierDefinition(easing)) {
|
|
297
172
|
return cubicBezierAsString(easing);
|
|
@@ -305,7 +180,7 @@ function mapEasingToNativeEasing(easing, duration) {
|
|
|
305
180
|
}
|
|
306
181
|
}
|
|
307
182
|
|
|
308
|
-
function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duration = 300, repeat = 0, repeatType = "loop", ease = "
|
|
183
|
+
function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duration = 300, repeat = 0, repeatType = "loop", ease = "easeOut", times, } = {}, pseudoElement = undefined) {
|
|
309
184
|
const keyframeOptions = {
|
|
310
185
|
[valueName]: keyframes,
|
|
311
186
|
};
|
|
@@ -317,15 +192,17 @@ function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duratio
|
|
|
317
192
|
*/
|
|
318
193
|
if (Array.isArray(easing))
|
|
319
194
|
keyframeOptions.easing = easing;
|
|
320
|
-
const
|
|
195
|
+
const options = {
|
|
321
196
|
delay,
|
|
322
197
|
duration,
|
|
323
198
|
easing: !Array.isArray(easing) ? easing : "linear",
|
|
324
199
|
fill: "both",
|
|
325
200
|
iterations: repeat + 1,
|
|
326
201
|
direction: repeatType === "reverse" ? "alternate" : "normal",
|
|
327
|
-
|
|
328
|
-
|
|
202
|
+
};
|
|
203
|
+
if (pseudoElement)
|
|
204
|
+
options.pseudoElement = pseudoElement;
|
|
205
|
+
const animation = element.animate(keyframeOptions, options);
|
|
329
206
|
return animation;
|
|
330
207
|
}
|
|
331
208
|
|
|
@@ -334,7 +211,7 @@ function isGenerator(type) {
|
|
|
334
211
|
}
|
|
335
212
|
|
|
336
213
|
function applyGeneratorOptions({ type, ...options }) {
|
|
337
|
-
if (isGenerator(type)) {
|
|
214
|
+
if (isGenerator(type) && supportsLinearEasing()) {
|
|
338
215
|
return type.applyToOptions(options);
|
|
339
216
|
}
|
|
340
217
|
else {
|
|
@@ -344,86 +221,81 @@ function applyGeneratorOptions({ type, ...options }) {
|
|
|
344
221
|
return options;
|
|
345
222
|
}
|
|
346
223
|
|
|
347
|
-
const animationMaps = new WeakMap();
|
|
348
|
-
const animationMapKey = (name, pseudoElement) => `${name}:${pseudoElement}`;
|
|
349
|
-
function getAnimationMap(element) {
|
|
350
|
-
const map = animationMaps.get(element) || new Map();
|
|
351
|
-
animationMaps.set(element, map);
|
|
352
|
-
return map;
|
|
353
|
-
}
|
|
354
224
|
/**
|
|
355
225
|
* NativeAnimation implements AnimationPlaybackControls for the browser's Web Animations API.
|
|
356
226
|
*/
|
|
357
|
-
class NativeAnimation {
|
|
227
|
+
class NativeAnimation extends WithPromise {
|
|
358
228
|
constructor(options) {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
if ("animation" in options) {
|
|
364
|
-
this.animation = options.animation;
|
|
229
|
+
super();
|
|
230
|
+
this.finishedTime = null;
|
|
231
|
+
this.isStopped = false;
|
|
232
|
+
if (!options)
|
|
365
233
|
return;
|
|
366
|
-
}
|
|
367
|
-
const { element, name, keyframes: unresolvedKeyframes, pseudoElement, allowFlatten = false, } = options;
|
|
368
|
-
let { transition } = options;
|
|
234
|
+
const { element, name, keyframes, pseudoElement, allowFlatten = false, finalKeyframe, } = options;
|
|
369
235
|
this.isPseudoElement = Boolean(pseudoElement);
|
|
370
236
|
this.allowFlatten = allowFlatten;
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
* TODO: Check for VisualElement before using animation state. This is a fallback
|
|
375
|
-
* for mini animate(). Do this when implementing NativeAnimationExtended.
|
|
376
|
-
*/
|
|
377
|
-
const animationMap = getAnimationMap(element);
|
|
378
|
-
const key = animationMapKey(name, pseudoElement || "");
|
|
379
|
-
const currentAnimation = animationMap.get(key);
|
|
380
|
-
currentAnimation && currentAnimation.stop();
|
|
381
|
-
/**
|
|
382
|
-
* TODO: If these keyframes aren't correctly hydrated then we want to throw
|
|
383
|
-
* run an instant animation.
|
|
384
|
-
*/
|
|
385
|
-
const keyframes = hydrateKeyframes(element, name, unresolvedKeyframes, pseudoElement);
|
|
386
|
-
invariant(typeof transition.type !== "string", `animateMini doesn't support "type" as a string. Did you mean to import { spring } from "motion"?`);
|
|
387
|
-
transition = applyGeneratorOptions(transition);
|
|
237
|
+
this.options = options;
|
|
238
|
+
invariant(typeof options.type !== "string", `animateMini doesn't support "type" as a string. Did you mean to import { spring } from "motion"?`);
|
|
239
|
+
const transition = applyGeneratorOptions(options);
|
|
388
240
|
this.animation = startWaapiAnimation(element, name, keyframes, transition, pseudoElement);
|
|
389
241
|
if (transition.autoplay === false) {
|
|
390
242
|
this.animation.pause();
|
|
391
243
|
}
|
|
392
|
-
this.removeAnimation = () => animationMap.delete(key);
|
|
393
244
|
this.animation.onfinish = () => {
|
|
245
|
+
this.finishedTime = this.time;
|
|
394
246
|
if (!pseudoElement) {
|
|
395
|
-
|
|
396
|
-
this.
|
|
247
|
+
const keyframe = getFinalKeyframe(keyframes, this.options, finalKeyframe, this.speed);
|
|
248
|
+
if (this.updateMotionValue) {
|
|
249
|
+
this.updateMotionValue(keyframe);
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
/**
|
|
253
|
+
* If we can, we want to commit the final style as set by the user,
|
|
254
|
+
* rather than the computed keyframe value supplied by the animation.
|
|
255
|
+
*/
|
|
256
|
+
setStyle(element, name, keyframe);
|
|
257
|
+
}
|
|
258
|
+
this.animation.cancel();
|
|
397
259
|
}
|
|
260
|
+
this.notifyFinished();
|
|
398
261
|
};
|
|
399
|
-
/**
|
|
400
|
-
* TODO: Check for VisualElement before using animation state.
|
|
401
|
-
*/
|
|
402
|
-
animationMap.set(key, this);
|
|
403
262
|
}
|
|
404
263
|
play() {
|
|
264
|
+
if (this.isStopped)
|
|
265
|
+
return;
|
|
405
266
|
this.animation.play();
|
|
267
|
+
if (this.state === "finished") {
|
|
268
|
+
this.updateFinished();
|
|
269
|
+
}
|
|
406
270
|
}
|
|
407
271
|
pause() {
|
|
408
272
|
this.animation.pause();
|
|
409
273
|
}
|
|
410
274
|
complete() {
|
|
411
|
-
this.animation.finish();
|
|
275
|
+
this.animation.finish?.();
|
|
412
276
|
}
|
|
413
277
|
cancel() {
|
|
414
278
|
try {
|
|
415
279
|
this.animation.cancel();
|
|
416
280
|
}
|
|
417
281
|
catch (e) { }
|
|
418
|
-
this.removeAnimation();
|
|
419
282
|
}
|
|
420
283
|
stop() {
|
|
284
|
+
if (this.isStopped)
|
|
285
|
+
return;
|
|
286
|
+
this.isStopped = true;
|
|
421
287
|
const { state } = this;
|
|
422
288
|
if (state === "idle" || state === "finished") {
|
|
423
289
|
return;
|
|
424
290
|
}
|
|
425
|
-
this.
|
|
426
|
-
|
|
291
|
+
if (this.updateMotionValue) {
|
|
292
|
+
this.updateMotionValue();
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
this.commitStyles();
|
|
296
|
+
}
|
|
297
|
+
if (!this.isPseudoElement)
|
|
298
|
+
this.cancel();
|
|
427
299
|
}
|
|
428
300
|
/**
|
|
429
301
|
* WAAPI doesn't natively have any interruption capabilities.
|
|
@@ -443,13 +315,14 @@ class NativeAnimation {
|
|
|
443
315
|
}
|
|
444
316
|
}
|
|
445
317
|
get duration() {
|
|
446
|
-
const duration = this.animation.effect?.getComputedTiming().duration || 0;
|
|
318
|
+
const duration = this.animation.effect?.getComputedTiming?.().duration || 0;
|
|
447
319
|
return millisecondsToSeconds(Number(duration));
|
|
448
320
|
}
|
|
449
321
|
get time() {
|
|
450
322
|
return millisecondsToSeconds(Number(this.animation.currentTime) || 0);
|
|
451
323
|
}
|
|
452
324
|
set time(newTime) {
|
|
325
|
+
this.finishedTime = null;
|
|
453
326
|
this.animation.currentTime = secondsToMilliseconds(newTime);
|
|
454
327
|
}
|
|
455
328
|
/**
|
|
@@ -460,38 +333,123 @@ class NativeAnimation {
|
|
|
460
333
|
return this.animation.playbackRate;
|
|
461
334
|
}
|
|
462
335
|
set speed(newSpeed) {
|
|
336
|
+
// Allow backwards playback after finishing
|
|
337
|
+
if (newSpeed < 0)
|
|
338
|
+
this.finishedTime = null;
|
|
463
339
|
this.animation.playbackRate = newSpeed;
|
|
464
340
|
}
|
|
465
341
|
get state() {
|
|
466
|
-
return this.
|
|
342
|
+
return this.finishedTime !== null
|
|
343
|
+
? "finished"
|
|
344
|
+
: this.animation.playState;
|
|
467
345
|
}
|
|
468
346
|
get startTime() {
|
|
469
347
|
return Number(this.animation.startTime);
|
|
470
348
|
}
|
|
471
|
-
|
|
472
|
-
|
|
349
|
+
set startTime(newStartTime) {
|
|
350
|
+
this.animation.startTime = newStartTime;
|
|
473
351
|
}
|
|
474
|
-
|
|
352
|
+
/**
|
|
353
|
+
* Attaches a timeline to the animation, for instance the `ScrollTimeline`.
|
|
354
|
+
*/
|
|
355
|
+
attachTimeline({ timeline, observe }) {
|
|
475
356
|
if (this.allowFlatten) {
|
|
476
357
|
this.animation.effect?.updateTiming({ easing: "linear" });
|
|
477
358
|
}
|
|
359
|
+
this.animation.onfinish = null;
|
|
360
|
+
if (supportsScrollTimeline()) {
|
|
361
|
+
this.animation.timeline = timeline;
|
|
362
|
+
return noop;
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
return observe(this);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
class GroupAnimation {
|
|
371
|
+
constructor(animations) {
|
|
372
|
+
// Bound to accomadate common `return animation.stop` pattern
|
|
373
|
+
this.stop = () => this.runAll("stop");
|
|
374
|
+
this.animations = animations.filter(Boolean);
|
|
375
|
+
}
|
|
376
|
+
get finished() {
|
|
377
|
+
return Promise.all(this.animations.map((animation) => animation.finished));
|
|
478
378
|
}
|
|
479
379
|
/**
|
|
480
|
-
*
|
|
380
|
+
* TODO: Filter out cancelled or stopped animations before returning
|
|
481
381
|
*/
|
|
382
|
+
getAll(propName) {
|
|
383
|
+
return this.animations[0][propName];
|
|
384
|
+
}
|
|
385
|
+
setAll(propName, newValue) {
|
|
386
|
+
for (let i = 0; i < this.animations.length; i++) {
|
|
387
|
+
this.animations[i][propName] = newValue;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
482
390
|
attachTimeline(timeline) {
|
|
483
|
-
this.animation
|
|
484
|
-
|
|
485
|
-
|
|
391
|
+
const subscriptions = this.animations.map((animation) => animation.attachTimeline(timeline));
|
|
392
|
+
return () => {
|
|
393
|
+
subscriptions.forEach((cancel, i) => {
|
|
394
|
+
cancel && cancel();
|
|
395
|
+
this.animations[i].stop();
|
|
396
|
+
});
|
|
397
|
+
};
|
|
486
398
|
}
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
399
|
+
get time() {
|
|
400
|
+
return this.getAll("time");
|
|
401
|
+
}
|
|
402
|
+
set time(time) {
|
|
403
|
+
this.setAll("time", time);
|
|
404
|
+
}
|
|
405
|
+
get speed() {
|
|
406
|
+
return this.getAll("speed");
|
|
407
|
+
}
|
|
408
|
+
set speed(speed) {
|
|
409
|
+
this.setAll("speed", speed);
|
|
410
|
+
}
|
|
411
|
+
get state() {
|
|
412
|
+
return this.getAll("state");
|
|
494
413
|
}
|
|
414
|
+
get startTime() {
|
|
415
|
+
return this.getAll("startTime");
|
|
416
|
+
}
|
|
417
|
+
get duration() {
|
|
418
|
+
let max = 0;
|
|
419
|
+
for (let i = 0; i < this.animations.length; i++) {
|
|
420
|
+
max = Math.max(max, this.animations[i].duration);
|
|
421
|
+
}
|
|
422
|
+
return max;
|
|
423
|
+
}
|
|
424
|
+
runAll(methodName) {
|
|
425
|
+
this.animations.forEach((controls) => controls[methodName]());
|
|
426
|
+
}
|
|
427
|
+
play() {
|
|
428
|
+
this.runAll("play");
|
|
429
|
+
}
|
|
430
|
+
pause() {
|
|
431
|
+
this.runAll("pause");
|
|
432
|
+
}
|
|
433
|
+
cancel() {
|
|
434
|
+
this.runAll("cancel");
|
|
435
|
+
}
|
|
436
|
+
complete() {
|
|
437
|
+
this.runAll("complete");
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
class GroupAnimationWithThen extends GroupAnimation {
|
|
442
|
+
then(onResolve, _onReject) {
|
|
443
|
+
return this.finished.finally(onResolve).then(() => { });
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
const animationMaps = new WeakMap();
|
|
448
|
+
const animationMapKey = (name, pseudoElement = "") => `${name}:${pseudoElement}`;
|
|
449
|
+
function getAnimationMap(element) {
|
|
450
|
+
const map = animationMaps.get(element) || new Map();
|
|
451
|
+
animationMaps.set(element, map);
|
|
452
|
+
return map;
|
|
495
453
|
}
|
|
496
454
|
|
|
497
455
|
function getValueTransition(transition, key) {
|
|
@@ -500,6 +458,52 @@ function getValueTransition(transition, key) {
|
|
|
500
458
|
transition);
|
|
501
459
|
}
|
|
502
460
|
|
|
461
|
+
const pxValues = new Set([
|
|
462
|
+
// Border props
|
|
463
|
+
"borderWidth",
|
|
464
|
+
"borderTopWidth",
|
|
465
|
+
"borderRightWidth",
|
|
466
|
+
"borderBottomWidth",
|
|
467
|
+
"borderLeftWidth",
|
|
468
|
+
"borderRadius",
|
|
469
|
+
"radius",
|
|
470
|
+
"borderTopLeftRadius",
|
|
471
|
+
"borderTopRightRadius",
|
|
472
|
+
"borderBottomRightRadius",
|
|
473
|
+
"borderBottomLeftRadius",
|
|
474
|
+
// Positioning props
|
|
475
|
+
"width",
|
|
476
|
+
"maxWidth",
|
|
477
|
+
"height",
|
|
478
|
+
"maxHeight",
|
|
479
|
+
"top",
|
|
480
|
+
"right",
|
|
481
|
+
"bottom",
|
|
482
|
+
"left",
|
|
483
|
+
// Spacing props
|
|
484
|
+
"padding",
|
|
485
|
+
"paddingTop",
|
|
486
|
+
"paddingRight",
|
|
487
|
+
"paddingBottom",
|
|
488
|
+
"paddingLeft",
|
|
489
|
+
"margin",
|
|
490
|
+
"marginTop",
|
|
491
|
+
"marginRight",
|
|
492
|
+
"marginBottom",
|
|
493
|
+
"marginLeft",
|
|
494
|
+
// Misc
|
|
495
|
+
"backgroundPositionX",
|
|
496
|
+
"backgroundPositionY",
|
|
497
|
+
]);
|
|
498
|
+
|
|
499
|
+
function applyPxDefaults(keyframes, name) {
|
|
500
|
+
for (let i = 0; i < keyframes.length; i++) {
|
|
501
|
+
if (typeof keyframes[i] === "number" && pxValues.has(name)) {
|
|
502
|
+
keyframes[i] = keyframes[i] + "px";
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
503
507
|
function resolveElements(elementOrSelector, scope, selectorCache) {
|
|
504
508
|
if (elementOrSelector instanceof EventTarget) {
|
|
505
509
|
return [elementOrSelector];
|
|
@@ -516,11 +520,38 @@ function resolveElements(elementOrSelector, scope, selectorCache) {
|
|
|
516
520
|
return Array.from(elementOrSelector);
|
|
517
521
|
}
|
|
518
522
|
|
|
523
|
+
function getComputedStyle(element, name) {
|
|
524
|
+
const computedStyle = window.getComputedStyle(element);
|
|
525
|
+
return isCSSVar(name)
|
|
526
|
+
? computedStyle.getPropertyValue(name)
|
|
527
|
+
: computedStyle[name];
|
|
528
|
+
}
|
|
529
|
+
|
|
519
530
|
function animateElements(elementOrSelector, keyframes, options, scope) {
|
|
520
531
|
const elements = resolveElements(elementOrSelector, scope);
|
|
521
532
|
const numElements = elements.length;
|
|
522
533
|
invariant(Boolean(numElements), "No valid element provided.");
|
|
523
|
-
|
|
534
|
+
/**
|
|
535
|
+
* WAAPI doesn't support interrupting animations.
|
|
536
|
+
*
|
|
537
|
+
* Therefore, starting animations requires a three-step process:
|
|
538
|
+
* 1. Stop existing animations (write styles to DOM)
|
|
539
|
+
* 2. Resolve keyframes (read styles from DOM)
|
|
540
|
+
* 3. Create new animations (write styles to DOM)
|
|
541
|
+
*
|
|
542
|
+
* The hybrid `animate()` function uses AsyncAnimation to resolve
|
|
543
|
+
* keyframes before creating new animations, which removes style
|
|
544
|
+
* thrashing. Here, we have much stricter filesize constraints.
|
|
545
|
+
* Therefore we do this in a synchronous way that ensures that
|
|
546
|
+
* at least within `animate()` calls there is no style thrashing.
|
|
547
|
+
*
|
|
548
|
+
* In the motion-native-animate-mini-interrupt benchmark this
|
|
549
|
+
* was 80% faster than a single loop.
|
|
550
|
+
*/
|
|
551
|
+
const animationDefinitions = [];
|
|
552
|
+
/**
|
|
553
|
+
* Step 1: Build options and stop existing animations (write)
|
|
554
|
+
*/
|
|
524
555
|
for (let i = 0; i < numElements; i++) {
|
|
525
556
|
const element = elements[i];
|
|
526
557
|
const elementTransition = { ...options };
|
|
@@ -531,21 +562,69 @@ function animateElements(elementOrSelector, keyframes, options, scope) {
|
|
|
531
562
|
elementTransition.delay = elementTransition.delay(i, numElements);
|
|
532
563
|
}
|
|
533
564
|
for (const valueName in keyframes) {
|
|
534
|
-
|
|
565
|
+
let valueKeyframes = keyframes[valueName];
|
|
566
|
+
if (!Array.isArray(valueKeyframes)) {
|
|
567
|
+
valueKeyframes = [valueKeyframes];
|
|
568
|
+
}
|
|
535
569
|
const valueOptions = {
|
|
536
570
|
...getValueTransition(elementTransition, valueName),
|
|
537
571
|
};
|
|
538
572
|
valueOptions.duration && (valueOptions.duration = secondsToMilliseconds(valueOptions.duration));
|
|
539
573
|
valueOptions.delay && (valueOptions.delay = secondsToMilliseconds(valueOptions.delay));
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
574
|
+
/**
|
|
575
|
+
* If there's an existing animation playing on this element then stop it
|
|
576
|
+
* before creating a new one.
|
|
577
|
+
*/
|
|
578
|
+
const map = getAnimationMap(element);
|
|
579
|
+
const key = animationMapKey(valueName, valueOptions.pseudoElement || "");
|
|
580
|
+
const currentAnimation = map.get(key);
|
|
581
|
+
currentAnimation && currentAnimation.stop();
|
|
582
|
+
animationDefinitions.push({
|
|
583
|
+
map,
|
|
584
|
+
key,
|
|
585
|
+
unresolvedKeyframes: valueKeyframes,
|
|
586
|
+
options: {
|
|
587
|
+
...valueOptions,
|
|
588
|
+
element,
|
|
589
|
+
name: valueName,
|
|
590
|
+
allowFlatten: !elementTransition.type && !elementTransition.ease,
|
|
591
|
+
},
|
|
592
|
+
});
|
|
547
593
|
}
|
|
548
594
|
}
|
|
595
|
+
/**
|
|
596
|
+
* Step 2: Resolve keyframes (read)
|
|
597
|
+
*/
|
|
598
|
+
for (let i = 0; i < animationDefinitions.length; i++) {
|
|
599
|
+
const { unresolvedKeyframes, options: animationOptions } = animationDefinitions[i];
|
|
600
|
+
const { element, name, pseudoElement } = animationOptions;
|
|
601
|
+
if (!pseudoElement && unresolvedKeyframes[0] === null) {
|
|
602
|
+
unresolvedKeyframes[0] = getComputedStyle(element, name);
|
|
603
|
+
}
|
|
604
|
+
fillWildcards(unresolvedKeyframes);
|
|
605
|
+
applyPxDefaults(unresolvedKeyframes, name);
|
|
606
|
+
/**
|
|
607
|
+
* If we only have one keyframe, explicitly read the initial keyframe
|
|
608
|
+
* from the computed style. This is to ensure consistency with WAAPI behaviour
|
|
609
|
+
* for restarting animations, for instance .play() after finish, when it
|
|
610
|
+
* has one vs two keyframes.
|
|
611
|
+
*/
|
|
612
|
+
if (!pseudoElement && unresolvedKeyframes.length < 2) {
|
|
613
|
+
unresolvedKeyframes.unshift(getComputedStyle(element, name));
|
|
614
|
+
}
|
|
615
|
+
animationOptions.keyframes = unresolvedKeyframes;
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Step 3: Create new animations (write)
|
|
619
|
+
*/
|
|
620
|
+
const animations = [];
|
|
621
|
+
for (let i = 0; i < animationDefinitions.length; i++) {
|
|
622
|
+
const { map, key, options: animationOptions } = animationDefinitions[i];
|
|
623
|
+
const animation = new NativeAnimation(animationOptions);
|
|
624
|
+
map.set(key, animation);
|
|
625
|
+
animation.finished.finally(() => map.delete(key));
|
|
626
|
+
animations.push(animation);
|
|
627
|
+
}
|
|
549
628
|
return animations;
|
|
550
629
|
}
|
|
551
630
|
|