motion 12.16.1-alpha.0 → 12.17.0-alpha.2
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/dist/cjs/debug.js +7 -294
- package/dist/cjs/index.js +6 -7531
- package/dist/cjs/mini.js +2 -2
- package/dist/cjs/react-client.js +6 -10157
- package/dist/cjs/react-m.js +6 -1780
- package/dist/cjs/react-mini.js +7 -642
- package/dist/es/framer-motion/dist/es/animation/hooks/use-animated-state.mjs +1 -1
- package/dist/es/framer-motion/dist/es/animation/hooks/use-animation.mjs +3 -3
- package/dist/es/framer-motion/dist/es/animation/sequence/create.mjs +1 -1
- package/dist/es/motion-dom/dist/es/animation/waapi/utils/linear.mjs +1 -1
- package/dist/motion.dev.js +2 -2
- package/dist/motion.js +1 -1
- package/package.json +3 -3
package/dist/cjs/react-mini.js
CHANGED
|
@@ -2,648 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var mini = require('framer-motion/mini');
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
* Creates a constant value over the lifecycle of a component.
|
|
9
|
-
*
|
|
10
|
-
* Even if `useMemo` is provided an empty array as its final argument, it doesn't offer
|
|
11
|
-
* a guarantee that it won't re-run for performance reasons later on. By using `useConstant`
|
|
12
|
-
* you can ensure that initialisers don't execute twice or more.
|
|
13
|
-
*/
|
|
14
|
-
function useConstant(init) {
|
|
15
|
-
const ref = react.useRef(null);
|
|
16
|
-
if (ref.current === null) {
|
|
17
|
-
ref.current = init();
|
|
18
|
-
}
|
|
19
|
-
return ref.current;
|
|
20
|
-
}
|
|
21
7
|
|
|
22
|
-
function useUnmountEffect(callback) {
|
|
23
|
-
return react.useEffect(() => () => callback(), []);
|
|
24
|
-
}
|
|
25
8
|
|
|
26
|
-
|
|
27
|
-
if (
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/*#__NO_SIDE_EFFECTS__*/
|
|
36
|
-
function memo(callback) {
|
|
37
|
-
let result;
|
|
38
|
-
return () => {
|
|
39
|
-
if (result === undefined)
|
|
40
|
-
result = callback();
|
|
41
|
-
return result;
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/*#__NO_SIDE_EFFECTS__*/
|
|
46
|
-
const noop = (any) => any;
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Converts seconds to milliseconds
|
|
50
|
-
*
|
|
51
|
-
* @param seconds - Time in seconds.
|
|
52
|
-
* @return milliseconds - Converted time in milliseconds.
|
|
53
|
-
*/
|
|
54
|
-
/*#__NO_SIDE_EFFECTS__*/
|
|
55
|
-
const secondsToMilliseconds = (seconds) => seconds * 1000;
|
|
56
|
-
/*#__NO_SIDE_EFFECTS__*/
|
|
57
|
-
const millisecondsToSeconds = (milliseconds) => milliseconds / 1000;
|
|
58
|
-
|
|
59
|
-
const isBezierDefinition = (easing) => Array.isArray(easing) && typeof easing[0] === "number";
|
|
60
|
-
|
|
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)) + ", ";
|
|
68
|
-
}
|
|
69
|
-
return `linear(${points.substring(0, points.length - 2)})`;
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const isNotNull = (value) => value !== null;
|
|
73
|
-
function getFinalKeyframe(keyframes, { repeat, repeatType = "loop" }, finalKeyframe, speed = 1) {
|
|
74
|
-
const resolvedKeyframes = keyframes.filter(isNotNull);
|
|
75
|
-
const useFirstKeyframe = speed < 0 || (repeat && repeatType !== "loop" && repeat % 2 === 1);
|
|
76
|
-
const index = useFirstKeyframe ? 0 : resolvedKeyframes.length - 1;
|
|
77
|
-
return !index || finalKeyframe === undefined
|
|
78
|
-
? resolvedKeyframes[index]
|
|
79
|
-
: finalKeyframe;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
class WithPromise {
|
|
83
|
-
constructor() {
|
|
84
|
-
this.updateFinished();
|
|
85
|
-
}
|
|
86
|
-
get finished() {
|
|
87
|
-
return this._finished;
|
|
88
|
-
}
|
|
89
|
-
updateFinished() {
|
|
90
|
-
this._finished = new Promise((resolve) => {
|
|
91
|
-
this.resolve = resolve;
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
notifyFinished() {
|
|
95
|
-
this.resolve();
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Allows the animation to be awaited.
|
|
99
|
-
*
|
|
100
|
-
* @deprecated Use `finished` instead.
|
|
101
|
-
*/
|
|
102
|
-
then(onResolve, onReject) {
|
|
103
|
-
return this.finished.then(onResolve, onReject);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function fillWildcards(keyframes) {
|
|
108
|
-
for (let i = 1; i < keyframes.length; i++) {
|
|
109
|
-
keyframes[i] ?? (keyframes[i] = keyframes[i - 1]);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const isCSSVar = (name) => name.startsWith("--");
|
|
114
|
-
|
|
115
|
-
function setStyle(element, name, value) {
|
|
116
|
-
isCSSVar(name)
|
|
117
|
-
? element.style.setProperty(name, value)
|
|
118
|
-
: (element.style[name] = value);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const supportsScrollTimeline = /* @__PURE__ */ memo(() => window.ScrollTimeline !== undefined);
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Add the ability for test suites to manually set support flags
|
|
125
|
-
* to better test more environments.
|
|
126
|
-
*/
|
|
127
|
-
const supportsFlags = {};
|
|
128
|
-
|
|
129
|
-
function memoSupports(callback, supportsFlag) {
|
|
130
|
-
const memoized = memo(callback);
|
|
131
|
-
return () => supportsFlags[supportsFlag] ?? memoized();
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const supportsLinearEasing = /*@__PURE__*/ memoSupports(() => {
|
|
135
|
-
try {
|
|
136
|
-
document
|
|
137
|
-
.createElement("div")
|
|
138
|
-
.animate({ opacity: 0 }, { easing: "linear(0, 1)" });
|
|
139
|
-
}
|
|
140
|
-
catch (e) {
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
return true;
|
|
144
|
-
}, "linearEasing");
|
|
145
|
-
|
|
146
|
-
const cubicBezierAsString = ([a, b, c, d]) => `cubic-bezier(${a}, ${b}, ${c}, ${d})`;
|
|
147
|
-
|
|
148
|
-
const supportedWaapiEasing = {
|
|
149
|
-
linear: "linear",
|
|
150
|
-
ease: "ease",
|
|
151
|
-
easeIn: "ease-in",
|
|
152
|
-
easeOut: "ease-out",
|
|
153
|
-
easeInOut: "ease-in-out",
|
|
154
|
-
circIn: /*@__PURE__*/ cubicBezierAsString([0, 0.65, 0.55, 1]),
|
|
155
|
-
circOut: /*@__PURE__*/ cubicBezierAsString([0.55, 0, 1, 0.45]),
|
|
156
|
-
backIn: /*@__PURE__*/ cubicBezierAsString([0.31, 0.01, 0.66, -0.59]),
|
|
157
|
-
backOut: /*@__PURE__*/ cubicBezierAsString([0.33, 1.53, 0.69, 0.99]),
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
function mapEasingToNativeEasing(easing, duration) {
|
|
161
|
-
if (!easing) {
|
|
162
|
-
return undefined;
|
|
163
|
-
}
|
|
164
|
-
else if (typeof easing === "function") {
|
|
165
|
-
return supportsLinearEasing()
|
|
166
|
-
? generateLinearEasing(easing, duration)
|
|
167
|
-
: "ease-out";
|
|
168
|
-
}
|
|
169
|
-
else if (isBezierDefinition(easing)) {
|
|
170
|
-
return cubicBezierAsString(easing);
|
|
171
|
-
}
|
|
172
|
-
else if (Array.isArray(easing)) {
|
|
173
|
-
return easing.map((segmentEasing) => mapEasingToNativeEasing(segmentEasing, duration) ||
|
|
174
|
-
supportedWaapiEasing.easeOut);
|
|
175
|
-
}
|
|
176
|
-
else {
|
|
177
|
-
return supportedWaapiEasing[easing];
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duration = 300, repeat = 0, repeatType = "loop", ease = "easeOut", times, } = {}, pseudoElement = undefined) {
|
|
182
|
-
const keyframeOptions = {
|
|
183
|
-
[valueName]: keyframes,
|
|
184
|
-
};
|
|
185
|
-
if (times)
|
|
186
|
-
keyframeOptions.offset = times;
|
|
187
|
-
const easing = mapEasingToNativeEasing(ease, duration);
|
|
188
|
-
/**
|
|
189
|
-
* If this is an easing array, apply to keyframes, not animation as a whole
|
|
190
|
-
*/
|
|
191
|
-
if (Array.isArray(easing))
|
|
192
|
-
keyframeOptions.easing = easing;
|
|
193
|
-
const options = {
|
|
194
|
-
delay,
|
|
195
|
-
duration,
|
|
196
|
-
easing: !Array.isArray(easing) ? easing : "linear",
|
|
197
|
-
fill: "both",
|
|
198
|
-
iterations: repeat + 1,
|
|
199
|
-
direction: repeatType === "reverse" ? "alternate" : "normal",
|
|
200
|
-
};
|
|
201
|
-
if (pseudoElement)
|
|
202
|
-
options.pseudoElement = pseudoElement;
|
|
203
|
-
const animation = element.animate(keyframeOptions, options);
|
|
204
|
-
return animation;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
function isGenerator(type) {
|
|
208
|
-
return typeof type === "function" && "applyToOptions" in type;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
function applyGeneratorOptions({ type, ...options }) {
|
|
212
|
-
if (isGenerator(type) && supportsLinearEasing()) {
|
|
213
|
-
return type.applyToOptions(options);
|
|
214
|
-
}
|
|
215
|
-
else {
|
|
216
|
-
options.duration ?? (options.duration = 300);
|
|
217
|
-
options.ease ?? (options.ease = "easeOut");
|
|
218
|
-
}
|
|
219
|
-
return options;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* NativeAnimation implements AnimationPlaybackControls for the browser's Web Animations API.
|
|
224
|
-
*/
|
|
225
|
-
class NativeAnimation extends WithPromise {
|
|
226
|
-
constructor(options) {
|
|
227
|
-
super();
|
|
228
|
-
this.finishedTime = null;
|
|
229
|
-
this.isStopped = false;
|
|
230
|
-
if (!options)
|
|
231
|
-
return;
|
|
232
|
-
const { element, name, keyframes, pseudoElement, allowFlatten = false, finalKeyframe, onComplete, } = options;
|
|
233
|
-
this.isPseudoElement = Boolean(pseudoElement);
|
|
234
|
-
this.allowFlatten = allowFlatten;
|
|
235
|
-
this.options = options;
|
|
236
|
-
invariant(typeof options.type !== "string", `animateMini doesn't support "type" as a string. Did you mean to import { spring } from "motion"?`);
|
|
237
|
-
const transition = applyGeneratorOptions(options);
|
|
238
|
-
this.animation = startWaapiAnimation(element, name, keyframes, transition, pseudoElement);
|
|
239
|
-
if (transition.autoplay === false) {
|
|
240
|
-
this.animation.pause();
|
|
241
|
-
}
|
|
242
|
-
this.animation.onfinish = () => {
|
|
243
|
-
this.finishedTime = this.time;
|
|
244
|
-
if (!pseudoElement) {
|
|
245
|
-
const keyframe = getFinalKeyframe(keyframes, this.options, finalKeyframe, this.speed);
|
|
246
|
-
if (this.updateMotionValue) {
|
|
247
|
-
this.updateMotionValue(keyframe);
|
|
248
|
-
}
|
|
249
|
-
else {
|
|
250
|
-
/**
|
|
251
|
-
* If we can, we want to commit the final style as set by the user,
|
|
252
|
-
* rather than the computed keyframe value supplied by the animation.
|
|
253
|
-
*/
|
|
254
|
-
setStyle(element, name, keyframe);
|
|
255
|
-
}
|
|
256
|
-
this.animation.cancel();
|
|
257
|
-
}
|
|
258
|
-
onComplete?.();
|
|
259
|
-
this.notifyFinished();
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
play() {
|
|
263
|
-
if (this.isStopped)
|
|
264
|
-
return;
|
|
265
|
-
this.animation.play();
|
|
266
|
-
if (this.state === "finished") {
|
|
267
|
-
this.updateFinished();
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
pause() {
|
|
271
|
-
this.animation.pause();
|
|
272
|
-
}
|
|
273
|
-
complete() {
|
|
274
|
-
this.animation.finish?.();
|
|
275
|
-
}
|
|
276
|
-
cancel() {
|
|
277
|
-
try {
|
|
278
|
-
this.animation.cancel();
|
|
279
|
-
}
|
|
280
|
-
catch (e) { }
|
|
281
|
-
}
|
|
282
|
-
stop() {
|
|
283
|
-
if (this.isStopped)
|
|
284
|
-
return;
|
|
285
|
-
this.isStopped = true;
|
|
286
|
-
const { state } = this;
|
|
287
|
-
if (state === "idle" || state === "finished") {
|
|
288
|
-
return;
|
|
289
|
-
}
|
|
290
|
-
if (this.updateMotionValue) {
|
|
291
|
-
this.updateMotionValue();
|
|
292
|
-
}
|
|
293
|
-
else {
|
|
294
|
-
this.commitStyles();
|
|
295
|
-
}
|
|
296
|
-
if (!this.isPseudoElement)
|
|
297
|
-
this.cancel();
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* WAAPI doesn't natively have any interruption capabilities.
|
|
301
|
-
*
|
|
302
|
-
* In this method, we commit styles back to the DOM before cancelling
|
|
303
|
-
* the animation.
|
|
304
|
-
*
|
|
305
|
-
* This is designed to be overridden by NativeAnimationExtended, which
|
|
306
|
-
* will create a renderless JS animation and sample it twice to calculate
|
|
307
|
-
* its current value, "previous" value, and therefore allow
|
|
308
|
-
* Motion to also correctly calculate velocity for any subsequent animation
|
|
309
|
-
* while deferring the commit until the next animation frame.
|
|
310
|
-
*/
|
|
311
|
-
commitStyles() {
|
|
312
|
-
if (!this.isPseudoElement) {
|
|
313
|
-
this.animation.commitStyles?.();
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
get duration() {
|
|
317
|
-
const duration = this.animation.effect?.getComputedTiming?.().duration || 0;
|
|
318
|
-
return millisecondsToSeconds(Number(duration));
|
|
319
|
-
}
|
|
320
|
-
get time() {
|
|
321
|
-
return millisecondsToSeconds(Number(this.animation.currentTime) || 0);
|
|
322
|
-
}
|
|
323
|
-
set time(newTime) {
|
|
324
|
-
this.finishedTime = null;
|
|
325
|
-
this.animation.currentTime = secondsToMilliseconds(newTime);
|
|
326
|
-
}
|
|
327
|
-
/**
|
|
328
|
-
* The playback speed of the animation.
|
|
329
|
-
* 1 = normal speed, 2 = double speed, 0.5 = half speed.
|
|
330
|
-
*/
|
|
331
|
-
get speed() {
|
|
332
|
-
return this.animation.playbackRate;
|
|
333
|
-
}
|
|
334
|
-
set speed(newSpeed) {
|
|
335
|
-
// Allow backwards playback after finishing
|
|
336
|
-
if (newSpeed < 0)
|
|
337
|
-
this.finishedTime = null;
|
|
338
|
-
this.animation.playbackRate = newSpeed;
|
|
339
|
-
}
|
|
340
|
-
get state() {
|
|
341
|
-
return this.finishedTime !== null
|
|
342
|
-
? "finished"
|
|
343
|
-
: this.animation.playState;
|
|
344
|
-
}
|
|
345
|
-
get startTime() {
|
|
346
|
-
return Number(this.animation.startTime);
|
|
347
|
-
}
|
|
348
|
-
set startTime(newStartTime) {
|
|
349
|
-
this.animation.startTime = newStartTime;
|
|
350
|
-
}
|
|
351
|
-
/**
|
|
352
|
-
* Attaches a timeline to the animation, for instance the `ScrollTimeline`.
|
|
353
|
-
*/
|
|
354
|
-
attachTimeline({ timeline, observe }) {
|
|
355
|
-
if (this.allowFlatten) {
|
|
356
|
-
this.animation.effect?.updateTiming({ easing: "linear" });
|
|
357
|
-
}
|
|
358
|
-
this.animation.onfinish = null;
|
|
359
|
-
if (timeline && supportsScrollTimeline()) {
|
|
360
|
-
this.animation.timeline = timeline;
|
|
361
|
-
return noop;
|
|
362
|
-
}
|
|
363
|
-
else {
|
|
364
|
-
return observe(this);
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
class GroupAnimation {
|
|
370
|
-
constructor(animations) {
|
|
371
|
-
// Bound to accomadate common `return animation.stop` pattern
|
|
372
|
-
this.stop = () => this.runAll("stop");
|
|
373
|
-
this.animations = animations.filter(Boolean);
|
|
374
|
-
}
|
|
375
|
-
get finished() {
|
|
376
|
-
return Promise.all(this.animations.map((animation) => animation.finished));
|
|
377
|
-
}
|
|
378
|
-
/**
|
|
379
|
-
* TODO: Filter out cancelled or stopped animations before returning
|
|
380
|
-
*/
|
|
381
|
-
getAll(propName) {
|
|
382
|
-
return this.animations[0][propName];
|
|
383
|
-
}
|
|
384
|
-
setAll(propName, newValue) {
|
|
385
|
-
for (let i = 0; i < this.animations.length; i++) {
|
|
386
|
-
this.animations[i][propName] = newValue;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
attachTimeline(timeline) {
|
|
390
|
-
const subscriptions = this.animations.map((animation) => animation.attachTimeline(timeline));
|
|
391
|
-
return () => {
|
|
392
|
-
subscriptions.forEach((cancel, i) => {
|
|
393
|
-
cancel && cancel();
|
|
394
|
-
this.animations[i].stop();
|
|
395
|
-
});
|
|
396
|
-
};
|
|
397
|
-
}
|
|
398
|
-
get time() {
|
|
399
|
-
return this.getAll("time");
|
|
400
|
-
}
|
|
401
|
-
set time(time) {
|
|
402
|
-
this.setAll("time", time);
|
|
403
|
-
}
|
|
404
|
-
get speed() {
|
|
405
|
-
return this.getAll("speed");
|
|
406
|
-
}
|
|
407
|
-
set speed(speed) {
|
|
408
|
-
this.setAll("speed", speed);
|
|
409
|
-
}
|
|
410
|
-
get state() {
|
|
411
|
-
return this.getAll("state");
|
|
412
|
-
}
|
|
413
|
-
get startTime() {
|
|
414
|
-
return this.getAll("startTime");
|
|
415
|
-
}
|
|
416
|
-
get duration() {
|
|
417
|
-
let max = 0;
|
|
418
|
-
for (let i = 0; i < this.animations.length; i++) {
|
|
419
|
-
max = Math.max(max, this.animations[i].duration);
|
|
420
|
-
}
|
|
421
|
-
return max;
|
|
422
|
-
}
|
|
423
|
-
runAll(methodName) {
|
|
424
|
-
this.animations.forEach((controls) => controls[methodName]());
|
|
425
|
-
}
|
|
426
|
-
play() {
|
|
427
|
-
this.runAll("play");
|
|
428
|
-
}
|
|
429
|
-
pause() {
|
|
430
|
-
this.runAll("pause");
|
|
431
|
-
}
|
|
432
|
-
cancel() {
|
|
433
|
-
this.runAll("cancel");
|
|
434
|
-
}
|
|
435
|
-
complete() {
|
|
436
|
-
this.runAll("complete");
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
class GroupAnimationWithThen extends GroupAnimation {
|
|
441
|
-
then(onResolve, _onReject) {
|
|
442
|
-
return this.finished.finally(onResolve).then(() => { });
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
const animationMaps = new WeakMap();
|
|
447
|
-
const animationMapKey = (name, pseudoElement = "") => `${name}:${pseudoElement}`;
|
|
448
|
-
function getAnimationMap(element) {
|
|
449
|
-
const map = animationMaps.get(element) || new Map();
|
|
450
|
-
animationMaps.set(element, map);
|
|
451
|
-
return map;
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
function getValueTransition(transition, key) {
|
|
455
|
-
return (transition?.[key] ??
|
|
456
|
-
transition?.["default"] ??
|
|
457
|
-
transition);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
const pxValues = new Set([
|
|
461
|
-
// Border props
|
|
462
|
-
"borderWidth",
|
|
463
|
-
"borderTopWidth",
|
|
464
|
-
"borderRightWidth",
|
|
465
|
-
"borderBottomWidth",
|
|
466
|
-
"borderLeftWidth",
|
|
467
|
-
"borderRadius",
|
|
468
|
-
"radius",
|
|
469
|
-
"borderTopLeftRadius",
|
|
470
|
-
"borderTopRightRadius",
|
|
471
|
-
"borderBottomRightRadius",
|
|
472
|
-
"borderBottomLeftRadius",
|
|
473
|
-
// Positioning props
|
|
474
|
-
"width",
|
|
475
|
-
"maxWidth",
|
|
476
|
-
"height",
|
|
477
|
-
"maxHeight",
|
|
478
|
-
"top",
|
|
479
|
-
"right",
|
|
480
|
-
"bottom",
|
|
481
|
-
"left",
|
|
482
|
-
// Spacing props
|
|
483
|
-
"padding",
|
|
484
|
-
"paddingTop",
|
|
485
|
-
"paddingRight",
|
|
486
|
-
"paddingBottom",
|
|
487
|
-
"paddingLeft",
|
|
488
|
-
"margin",
|
|
489
|
-
"marginTop",
|
|
490
|
-
"marginRight",
|
|
491
|
-
"marginBottom",
|
|
492
|
-
"marginLeft",
|
|
493
|
-
// Misc
|
|
494
|
-
"backgroundPositionX",
|
|
495
|
-
"backgroundPositionY",
|
|
496
|
-
]);
|
|
497
|
-
|
|
498
|
-
function applyPxDefaults(keyframes, name) {
|
|
499
|
-
for (let i = 0; i < keyframes.length; i++) {
|
|
500
|
-
if (typeof keyframes[i] === "number" && pxValues.has(name)) {
|
|
501
|
-
keyframes[i] = keyframes[i] + "px";
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
function resolveElements(elementOrSelector, scope, selectorCache) {
|
|
507
|
-
if (elementOrSelector instanceof EventTarget) {
|
|
508
|
-
return [elementOrSelector];
|
|
509
|
-
}
|
|
510
|
-
else if (typeof elementOrSelector === "string") {
|
|
511
|
-
let root = document;
|
|
512
|
-
if (scope) {
|
|
513
|
-
root = scope.current;
|
|
514
|
-
}
|
|
515
|
-
const elements = selectorCache?.[elementOrSelector] ??
|
|
516
|
-
root.querySelectorAll(elementOrSelector);
|
|
517
|
-
return elements ? Array.from(elements) : [];
|
|
518
|
-
}
|
|
519
|
-
return Array.from(elementOrSelector);
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
function getComputedStyle(element, name) {
|
|
523
|
-
const computedStyle = window.getComputedStyle(element);
|
|
524
|
-
return isCSSVar(name)
|
|
525
|
-
? computedStyle.getPropertyValue(name)
|
|
526
|
-
: computedStyle[name];
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
function animateElements(elementOrSelector, keyframes, options, scope) {
|
|
530
|
-
const elements = resolveElements(elementOrSelector, scope);
|
|
531
|
-
const numElements = elements.length;
|
|
532
|
-
invariant(Boolean(numElements), "No valid element provided.");
|
|
533
|
-
/**
|
|
534
|
-
* WAAPI doesn't support interrupting animations.
|
|
535
|
-
*
|
|
536
|
-
* Therefore, starting animations requires a three-step process:
|
|
537
|
-
* 1. Stop existing animations (write styles to DOM)
|
|
538
|
-
* 2. Resolve keyframes (read styles from DOM)
|
|
539
|
-
* 3. Create new animations (write styles to DOM)
|
|
540
|
-
*
|
|
541
|
-
* The hybrid `animate()` function uses AsyncAnimation to resolve
|
|
542
|
-
* keyframes before creating new animations, which removes style
|
|
543
|
-
* thrashing. Here, we have much stricter filesize constraints.
|
|
544
|
-
* Therefore we do this in a synchronous way that ensures that
|
|
545
|
-
* at least within `animate()` calls there is no style thrashing.
|
|
546
|
-
*
|
|
547
|
-
* In the motion-native-animate-mini-interrupt benchmark this
|
|
548
|
-
* was 80% faster than a single loop.
|
|
549
|
-
*/
|
|
550
|
-
const animationDefinitions = [];
|
|
551
|
-
/**
|
|
552
|
-
* Step 1: Build options and stop existing animations (write)
|
|
553
|
-
*/
|
|
554
|
-
for (let i = 0; i < numElements; i++) {
|
|
555
|
-
const element = elements[i];
|
|
556
|
-
const elementTransition = { ...options };
|
|
557
|
-
/**
|
|
558
|
-
* Resolve stagger function if provided.
|
|
559
|
-
*/
|
|
560
|
-
if (typeof elementTransition.delay === "function") {
|
|
561
|
-
elementTransition.delay = elementTransition.delay(i, numElements);
|
|
562
|
-
}
|
|
563
|
-
for (const valueName in keyframes) {
|
|
564
|
-
let valueKeyframes = keyframes[valueName];
|
|
565
|
-
if (!Array.isArray(valueKeyframes)) {
|
|
566
|
-
valueKeyframes = [valueKeyframes];
|
|
567
|
-
}
|
|
568
|
-
const valueOptions = {
|
|
569
|
-
...getValueTransition(elementTransition, valueName),
|
|
570
|
-
};
|
|
571
|
-
valueOptions.duration && (valueOptions.duration = secondsToMilliseconds(valueOptions.duration));
|
|
572
|
-
valueOptions.delay && (valueOptions.delay = secondsToMilliseconds(valueOptions.delay));
|
|
573
|
-
/**
|
|
574
|
-
* If there's an existing animation playing on this element then stop it
|
|
575
|
-
* before creating a new one.
|
|
576
|
-
*/
|
|
577
|
-
const map = getAnimationMap(element);
|
|
578
|
-
const key = animationMapKey(valueName, valueOptions.pseudoElement || "");
|
|
579
|
-
const currentAnimation = map.get(key);
|
|
580
|
-
currentAnimation && currentAnimation.stop();
|
|
581
|
-
animationDefinitions.push({
|
|
582
|
-
map,
|
|
583
|
-
key,
|
|
584
|
-
unresolvedKeyframes: valueKeyframes,
|
|
585
|
-
options: {
|
|
586
|
-
...valueOptions,
|
|
587
|
-
element,
|
|
588
|
-
name: valueName,
|
|
589
|
-
allowFlatten: !elementTransition.type && !elementTransition.ease,
|
|
590
|
-
},
|
|
591
|
-
});
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
/**
|
|
595
|
-
* Step 2: Resolve keyframes (read)
|
|
596
|
-
*/
|
|
597
|
-
for (let i = 0; i < animationDefinitions.length; i++) {
|
|
598
|
-
const { unresolvedKeyframes, options: animationOptions } = animationDefinitions[i];
|
|
599
|
-
const { element, name, pseudoElement } = animationOptions;
|
|
600
|
-
if (!pseudoElement && unresolvedKeyframes[0] === null) {
|
|
601
|
-
unresolvedKeyframes[0] = getComputedStyle(element, name);
|
|
602
|
-
}
|
|
603
|
-
fillWildcards(unresolvedKeyframes);
|
|
604
|
-
applyPxDefaults(unresolvedKeyframes, name);
|
|
605
|
-
/**
|
|
606
|
-
* If we only have one keyframe, explicitly read the initial keyframe
|
|
607
|
-
* from the computed style. This is to ensure consistency with WAAPI behaviour
|
|
608
|
-
* for restarting animations, for instance .play() after finish, when it
|
|
609
|
-
* has one vs two keyframes.
|
|
610
|
-
*/
|
|
611
|
-
if (!pseudoElement && unresolvedKeyframes.length < 2) {
|
|
612
|
-
unresolvedKeyframes.unshift(getComputedStyle(element, name));
|
|
613
|
-
}
|
|
614
|
-
animationOptions.keyframes = unresolvedKeyframes;
|
|
615
|
-
}
|
|
616
|
-
/**
|
|
617
|
-
* Step 3: Create new animations (write)
|
|
618
|
-
*/
|
|
619
|
-
const animations = [];
|
|
620
|
-
for (let i = 0; i < animationDefinitions.length; i++) {
|
|
621
|
-
const { map, key, options: animationOptions } = animationDefinitions[i];
|
|
622
|
-
const animation = new NativeAnimation(animationOptions);
|
|
623
|
-
map.set(key, animation);
|
|
624
|
-
animation.finished.finally(() => map.delete(key));
|
|
625
|
-
animations.push(animation);
|
|
626
|
-
}
|
|
627
|
-
return animations;
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
const createScopedWaapiAnimate = (scope) => {
|
|
631
|
-
function scopedAnimate(elementOrSelector, keyframes, options) {
|
|
632
|
-
return new GroupAnimationWithThen(animateElements(elementOrSelector, keyframes, options, scope));
|
|
633
|
-
}
|
|
634
|
-
return scopedAnimate;
|
|
635
|
-
};
|
|
636
|
-
|
|
637
|
-
function useAnimateMini() {
|
|
638
|
-
const scope = useConstant(() => ({
|
|
639
|
-
current: null, // Will be hydrated by React
|
|
640
|
-
animations: [],
|
|
641
|
-
}));
|
|
642
|
-
const animate = useConstant(() => createScopedWaapiAnimate(scope));
|
|
643
|
-
useUnmountEffect(() => {
|
|
644
|
-
scope.animations.forEach((animation) => animation.stop());
|
|
645
|
-
});
|
|
646
|
-
return [scope, animate];
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
exports.useAnimate = useAnimateMini;
|
|
9
|
+
Object.keys(mini).forEach(function (k) {
|
|
10
|
+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function () { return mini[k]; }
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useState, useLayoutEffect } from 'react';
|
|
2
|
+
import { useConstant } from '../../utils/use-constant.mjs';
|
|
2
3
|
import { makeUseVisualState } from '../../motion/utils/use-visual-state.mjs';
|
|
3
4
|
import { createBox } from '../../projection/geometry/models.mjs';
|
|
4
5
|
import { VisualElement } from '../../render/VisualElement.mjs';
|
|
5
|
-
import { useConstant } from '../../utils/use-constant.mjs';
|
|
6
6
|
import { animateVisualElement } from '../interfaces/visual-element.mjs';
|
|
7
7
|
|
|
8
8
|
const createObject = () => ({});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
import { animationControls } from './animation-controls.mjs';
|
|
1
2
|
import { useConstant } from '../../utils/use-constant.mjs';
|
|
2
3
|
import { useIsomorphicLayoutEffect } from '../../utils/use-isomorphic-effect.mjs';
|
|
3
|
-
import { animationControls } from './animation-controls.mjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Creates `
|
|
6
|
+
* Creates `AnimationControls`, which can be used to manually start, stop
|
|
7
7
|
* and sequence animations on one or more components.
|
|
8
8
|
*
|
|
9
|
-
* The returned `
|
|
9
|
+
* The returned `AnimationControls` should be passed to the `animate` property
|
|
10
10
|
* of the components you want to animate.
|
|
11
11
|
*
|
|
12
12
|
* These components can then be animated with the `start` method.
|
|
@@ -72,7 +72,7 @@ function createAnimationsFromSequence(sequence, { defaultTransition = {}, ...seq
|
|
|
72
72
|
const numKeyframes = valueKeyframesAsList.length;
|
|
73
73
|
const createGenerator = isGenerator(type)
|
|
74
74
|
? type
|
|
75
|
-
: generators?.[type
|
|
75
|
+
: generators?.[type];
|
|
76
76
|
if (numKeyframes <= 2 && createGenerator) {
|
|
77
77
|
/**
|
|
78
78
|
* As we're creating an easing function from a spring,
|
|
@@ -4,7 +4,7 @@ resolution = 10 // as milliseconds
|
|
|
4
4
|
let points = "";
|
|
5
5
|
const numPoints = Math.max(Math.round(duration / resolution), 2);
|
|
6
6
|
for (let i = 0; i < numPoints; i++) {
|
|
7
|
-
points += easing(i / (numPoints - 1)) + ", ";
|
|
7
|
+
points += Math.round(easing(i / (numPoints - 1)) * 10000) / 10000 + ", ";
|
|
8
8
|
}
|
|
9
9
|
return `linear(${points.substring(0, points.length - 2)})`;
|
|
10
10
|
};
|