motion 12.6.3-alpha.0 → 12.6.3

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.
Files changed (74) hide show
  1. package/dist/cjs/debug.js +12 -12
  2. package/dist/cjs/index.js +402 -352
  3. package/dist/cjs/mini.js +339 -352
  4. package/dist/cjs/react-client.js +169 -181
  5. package/dist/cjs/react-m.js +18 -22
  6. package/dist/cjs/react-mini.js +275 -336
  7. package/dist/es/framer-motion/dist/es/animation/animate/index.mjs +2 -2
  8. package/dist/es/framer-motion/dist/es/animation/animators/AcceleratedAnimation.mjs +7 -4
  9. package/dist/es/framer-motion/dist/es/animation/animators/MainThreadAnimation.mjs +8 -6
  10. package/dist/es/framer-motion/dist/es/animation/animators/waapi/animate-elements.mjs +10 -8
  11. package/dist/es/framer-motion/dist/es/animation/animators/waapi/animate-sequence.mjs +2 -2
  12. package/dist/es/framer-motion/dist/es/animation/animators/waapi/animate-style.mjs +2 -2
  13. package/dist/es/framer-motion/dist/es/animation/generators/spring/index.mjs +11 -1
  14. package/dist/es/framer-motion/dist/es/animation/interfaces/motion-value.mjs +3 -3
  15. package/dist/es/framer-motion/dist/es/animation/interfaces/visual-element-target.mjs +1 -2
  16. package/dist/es/framer-motion/dist/es/animation/interfaces/visual-element-variant.mjs +1 -2
  17. package/dist/es/framer-motion/dist/es/animation/optimized-appear/handoff.mjs +2 -4
  18. package/dist/es/framer-motion/dist/es/animation/optimized-appear/start.mjs +4 -6
  19. package/dist/es/framer-motion/dist/es/animation/sequence/create.mjs +3 -3
  20. package/dist/es/framer-motion/dist/es/animation/sequence/utils/calc-time.mjs +1 -2
  21. package/dist/es/framer-motion/dist/es/components/AnimatePresence/index.mjs +2 -2
  22. package/dist/es/framer-motion/dist/es/gestures/drag/VisualElementDragControls.mjs +5 -10
  23. package/dist/es/framer-motion/dist/es/motion/features/animation/index.mjs +1 -2
  24. package/dist/es/framer-motion/dist/es/motion/index.mjs +2 -3
  25. package/dist/es/framer-motion/dist/es/motion/utils/use-visual-element.mjs +3 -5
  26. package/dist/es/framer-motion/dist/es/projection/node/create-projection-node.mjs +19 -27
  27. package/dist/es/framer-motion/dist/es/projection/styles/transform.mjs +1 -1
  28. package/dist/es/framer-motion/dist/es/render/VisualElement.mjs +3 -4
  29. package/dist/es/framer-motion/dist/es/render/dom/DOMKeyframesResolver.mjs +1 -2
  30. package/dist/es/framer-motion/dist/es/render/dom/resize/handle-element.mjs +5 -6
  31. package/dist/es/framer-motion/dist/es/render/dom/scroll/track.mjs +1 -2
  32. package/dist/es/framer-motion/dist/es/render/dom/utils/css-variables-conversion.mjs +1 -1
  33. package/dist/es/framer-motion/dist/es/render/dom/utils/filter-props.mjs +1 -1
  34. package/dist/es/framer-motion/dist/es/render/html/utils/scrape-motion-values.mjs +1 -2
  35. package/dist/es/framer-motion/dist/es/render/utils/KeyframesResolver.mjs +2 -3
  36. package/dist/es/framer-motion/dist/es/render/utils/animation-state.mjs +3 -5
  37. package/dist/es/framer-motion/dist/es/render/utils/motion-values.mjs +1 -1
  38. package/dist/es/framer-motion/dist/es/render/utils/resolve-variants.mjs +1 -1
  39. package/dist/es/framer-motion/dist/es/utils/mix/complex.mjs +1 -2
  40. package/dist/es/framer-motion/dist/es/value/types/complex/index.mjs +2 -3
  41. package/dist/es/framer-motion/dist/es/value/use-scroll.mjs +2 -2
  42. package/dist/es/framer-motion/dist/es/value/use-will-change/add-will-change.mjs +0 -7
  43. package/dist/es/motion/lib/react.mjs +0 -1
  44. package/dist/es/motion-dom/dist/es/animation/{controls/BaseGroup.mjs → GroupAnimation.mjs} +4 -5
  45. package/dist/es/motion-dom/dist/es/animation/GroupAnimationWithThen.mjs +9 -0
  46. package/dist/es/motion-dom/dist/es/animation/NativeAnimation.mjs +161 -0
  47. package/dist/es/motion-dom/dist/es/animation/generators/utils/is-generator.mjs +1 -1
  48. package/dist/es/motion-dom/dist/es/animation/keyframes/get-final.mjs +12 -0
  49. package/dist/es/motion-dom/dist/es/animation/keyframes/hydrate.mjs +26 -0
  50. package/dist/es/motion-dom/dist/es/animation/utils/get-value-transition.mjs +3 -5
  51. package/dist/es/motion-dom/dist/es/animation/waapi/easing/cubic-bezier.mjs +3 -0
  52. package/dist/es/motion-dom/dist/es/animation/waapi/easing/is-supported.mjs +14 -0
  53. package/dist/es/motion-dom/dist/es/animation/waapi/easing/map-easing.mjs +26 -0
  54. package/dist/es/motion-dom/dist/es/animation/waapi/easing/supported.mjs +15 -0
  55. package/dist/es/{framer-motion/dist/es/animation/animators/waapi/index.mjs → motion-dom/dist/es/animation/waapi/start-waapi-animation.mjs} +8 -6
  56. package/dist/es/{framer-motion/dist/es/animation/animators/waapi/utils/supports-partial-keyframes.mjs → motion-dom/dist/es/animation/waapi/supports/partial-keyframes.mjs} +2 -2
  57. package/dist/es/motion-dom/dist/es/animation/waapi/utils/apply-generator.mjs +14 -0
  58. package/dist/es/motion-dom/dist/es/animation/waapi/utils/linear.mjs +1 -4
  59. package/dist/es/motion-dom/dist/es/animation/waapi/utils/px-values.mjs +39 -0
  60. package/dist/es/motion-dom/dist/es/gestures/press/index.mjs +1 -1
  61. package/dist/es/motion-dom/dist/es/render/dom/style.mjs +15 -0
  62. package/dist/es/motion-dom/dist/es/utils/resolve-elements.mjs +2 -7
  63. package/dist/es/motion-dom/dist/es/utils/supports/flags.mjs +1 -3
  64. package/dist/es/motion-dom/dist/es/utils/supports/memo.mjs +1 -1
  65. package/dist/es/motion-dom/dist/es/value/index.mjs +1 -1
  66. package/dist/es/motion-utils/dist/es/errors.mjs +2 -4
  67. package/dist/motion.dev.js +402 -352
  68. package/dist/motion.js +1 -1
  69. package/package.json +3 -3
  70. package/dist/es/framer-motion/dist/es/animation/animators/waapi/NativeAnimation.mjs +0 -116
  71. package/dist/es/framer-motion/dist/es/animation/animators/waapi/utils/style.mjs +0 -8
  72. package/dist/es/motion-dom/dist/es/animation/controls/Group.mjs +0 -13
  73. package/dist/es/motion-dom/dist/es/animation/waapi/NativeAnimationControls.mjs +0 -85
  74. package/dist/es/motion-dom/dist/es/animation/waapi/utils/easing.mjs +0 -44
package/dist/cjs/mini.js CHANGED
@@ -8,10 +8,7 @@ function removeItem(arr, item) {
8
8
  arr.splice(index, 1);
9
9
  }
10
10
 
11
- /*#__NO_SIDE_EFFECTS__*/
12
- const noop = (any) => any;
13
-
14
- let invariant = noop;
11
+ let invariant = () => { };
15
12
  if (process.env.NODE_ENV !== "production") {
16
13
  invariant = (check, message) => {
17
14
  if (!check) {
@@ -30,6 +27,9 @@ function memo(callback) {
30
27
  };
31
28
  }
32
29
 
30
+ /*#__NO_SIDE_EFFECTS__*/
31
+ const noop = (any) => any;
32
+
33
33
  /*
34
34
  Progress within given range
35
35
 
@@ -61,15 +61,14 @@ const millisecondsToSeconds = (milliseconds) => milliseconds / 1000;
61
61
 
62
62
  const supportsScrollTimeline = /* @__PURE__ */ memo(() => window.ScrollTimeline !== undefined);
63
63
 
64
- class BaseGroupPlaybackControls {
64
+ class GroupAnimation {
65
65
  constructor(animations) {
66
66
  // Bound to accomodate common `return animation.stop` pattern
67
67
  this.stop = () => this.runAll("stop");
68
68
  this.animations = animations.filter(Boolean);
69
69
  }
70
70
  get finished() {
71
- // Support for new finished Promise and legacy thennable API
72
- return Promise.all(this.animations.map((animation) => "finished" in animation ? animation.finished : animation));
71
+ return Promise.all(this.animations.map((animation) => animation.finished));
73
72
  }
74
73
  /**
75
74
  * TODO: Filter out cancelled or stopped animations before returning
@@ -140,141 +139,104 @@ class BaseGroupPlaybackControls {
140
139
  }
141
140
  }
142
141
 
143
- /**
144
- * TODO: This is a temporary class to support the legacy
145
- * thennable API
146
- */
147
- class GroupPlaybackControls extends BaseGroupPlaybackControls {
148
- then(onResolve, onReject) {
149
- return Promise.all(this.animations).then(onResolve).catch(onReject);
142
+ class GroupAnimationWithThen extends GroupAnimation {
143
+ then(onResolve, _onReject) {
144
+ return this.finished.finally(onResolve).then(() => { });
150
145
  }
151
146
  }
152
147
 
153
- function getValueTransition$1(transition, key) {
154
- return transition
155
- ? transition[key] ||
156
- transition["default"] ||
157
- transition
158
- : undefined;
159
- }
160
-
161
- /**
162
- * Implement a practical max duration for keyframe generation
163
- * to prevent infinite loops
164
- */
165
- const maxGeneratorDuration = 20000;
166
- function calcGeneratorDuration(generator) {
167
- let duration = 0;
168
- const timeStep = 50;
169
- let state = generator.next(duration);
170
- while (!state.done && duration < maxGeneratorDuration) {
171
- duration += timeStep;
172
- state = generator.next(duration);
173
- }
174
- return duration >= maxGeneratorDuration ? Infinity : duration;
175
- }
176
-
177
- /**
178
- * Create a progress => progress easing function from a generator.
179
- */
180
- function createGeneratorEasing(options, scale = 100, createGenerator) {
181
- const generator = createGenerator({ ...options, keyframes: [0, scale] });
182
- const duration = Math.min(calcGeneratorDuration(generator), maxGeneratorDuration);
183
- return {
184
- type: "keyframes",
185
- ease: (progress) => {
186
- return generator.next(duration * progress).value / scale;
187
- },
188
- duration: millisecondsToSeconds(duration),
189
- };
190
- }
191
-
192
- function isGenerator(type) {
193
- return typeof type === "function";
194
- }
148
+ const isCSSVar = (name) => name.startsWith("--");
149
+ const style = {
150
+ set: (element, name, value) => {
151
+ isCSSVar(name)
152
+ ? element.style.setProperty(name, value)
153
+ : (element.style[name] = value);
154
+ },
155
+ get: (element, name) => {
156
+ return isCSSVar(name)
157
+ ? element.style.getPropertyValue(name)
158
+ : element.style[name];
159
+ },
160
+ };
195
161
 
196
- function attachTimeline(animation, timeline) {
197
- animation.timeline = timeline;
198
- animation.onfinish = null;
162
+ const isNotNull = (value) => value !== null;
163
+ function getFinalKeyframe(keyframes, { repeat, repeatType = "loop" }, finalKeyframe) {
164
+ const resolvedKeyframes = keyframes.filter(isNotNull);
165
+ const index = repeat && repeatType !== "loop" && repeat % 2 === 1
166
+ ? 0
167
+ : resolvedKeyframes.length - 1;
168
+ return !index || finalKeyframe === undefined
169
+ ? resolvedKeyframes[index]
170
+ : finalKeyframe;
199
171
  }
200
172
 
201
- class NativeAnimationControls {
202
- constructor(animation) {
203
- this.animation = animation;
204
- }
205
- get duration() {
206
- var _a, _b, _c;
207
- const durationInMs = ((_b = (_a = this.animation) === null || _a === void 0 ? void 0 : _a.effect) === null || _b === void 0 ? void 0 : _b.getComputedTiming().duration) ||
208
- ((_c = this.options) === null || _c === void 0 ? void 0 : _c.duration) ||
209
- 300;
210
- return millisecondsToSeconds(Number(durationInMs));
211
- }
212
- get time() {
213
- var _a;
214
- if (this.animation) {
215
- return millisecondsToSeconds(((_a = this.animation) === null || _a === void 0 ? void 0 : _a.currentTime) || 0);
216
- }
217
- return 0;
218
- }
219
- set time(newTime) {
220
- if (this.animation) {
221
- this.animation.currentTime = secondsToMilliseconds(newTime);
222
- }
223
- }
224
- get speed() {
225
- return this.animation ? this.animation.playbackRate : 1;
226
- }
227
- set speed(newSpeed) {
228
- if (this.animation) {
229
- this.animation.playbackRate = newSpeed;
230
- }
231
- }
232
- get state() {
233
- return this.animation ? this.animation.playState : "finished";
234
- }
235
- get startTime() {
236
- return this.animation ? this.animation.startTime : null;
237
- }
238
- get finished() {
239
- return this.animation ? this.animation.finished : Promise.resolve();
173
+ const supportsPartialKeyframes = /*@__PURE__*/ memo(() => {
174
+ try {
175
+ document.createElement("div").animate({ opacity: [1] });
240
176
  }
241
- play() {
242
- this.animation && this.animation.play();
177
+ catch (e) {
178
+ return false;
243
179
  }
244
- pause() {
245
- this.animation && this.animation.pause();
180
+ return true;
181
+ });
182
+
183
+ const pxValues = new Set([
184
+ // Border props
185
+ "borderWidth",
186
+ "borderTopWidth",
187
+ "borderRightWidth",
188
+ "borderBottomWidth",
189
+ "borderLeftWidth",
190
+ "borderRadius",
191
+ "radius",
192
+ "borderTopLeftRadius",
193
+ "borderTopRightRadius",
194
+ "borderBottomRightRadius",
195
+ "borderBottomLeftRadius",
196
+ // Positioning props
197
+ "width",
198
+ "maxWidth",
199
+ "height",
200
+ "maxHeight",
201
+ "top",
202
+ "right",
203
+ "bottom",
204
+ "left",
205
+ // Spacing props
206
+ "padding",
207
+ "paddingTop",
208
+ "paddingRight",
209
+ "paddingBottom",
210
+ "paddingLeft",
211
+ "margin",
212
+ "marginTop",
213
+ "marginRight",
214
+ "marginBottom",
215
+ "marginLeft",
216
+ // Misc
217
+ "backgroundPositionX",
218
+ "backgroundPositionY",
219
+ ]);
220
+
221
+ function hydrateKeyframes(element, name, keyframes, pseudoElement) {
222
+ if (!Array.isArray(keyframes)) {
223
+ keyframes = [keyframes];
246
224
  }
247
- stop() {
248
- if (!this.animation ||
249
- this.state === "idle" ||
250
- this.state === "finished") {
251
- return;
225
+ for (let i = 0; i < keyframes.length; i++) {
226
+ if (keyframes[i] === null) {
227
+ keyframes[i] =
228
+ i === 0 && !pseudoElement
229
+ ? style.get(element, name)
230
+ : keyframes[i - 1];
252
231
  }
253
- if (this.animation.commitStyles) {
254
- this.animation.commitStyles();
232
+ if (typeof keyframes[i] === "number" && pxValues.has(name)) {
233
+ keyframes[i] = keyframes[i] + "px";
255
234
  }
256
- this.cancel();
257
- }
258
- flatten() {
259
- var _a, _b;
260
- if (!this.animation || !((_a = this.options) === null || _a === void 0 ? void 0 : _a.allowFlatten))
261
- return;
262
- (_b = this.animation.effect) === null || _b === void 0 ? void 0 : _b.updateTiming({ easing: "linear" });
263
235
  }
264
- attachTimeline(timeline) {
265
- if (this.animation)
266
- attachTimeline(this.animation, timeline);
267
- return noop;
268
- }
269
- complete() {
270
- this.animation && this.animation.finish();
271
- }
272
- cancel() {
273
- try {
274
- this.animation && this.animation.cancel();
275
- }
276
- catch (e) { }
236
+ if (!pseudoElement && !supportsPartialKeyframes() && keyframes.length < 2) {
237
+ keyframes.unshift(style.get(element, name));
277
238
  }
239
+ return keyframes;
278
240
  }
279
241
 
280
242
  const isBezierDefinition = (easing) => Array.isArray(easing) && typeof easing[0] === "number";
@@ -283,13 +245,11 @@ const isBezierDefinition = (easing) => Array.isArray(easing) && typeof easing[0]
283
245
  * Add the ability for test suites to manually set support flags
284
246
  * to better test more environments.
285
247
  */
286
- const supportsFlags = {
287
- linearEasing: undefined,
288
- };
248
+ const supportsFlags = {};
289
249
 
290
250
  function memoSupports(callback, supportsFlag) {
291
251
  const memoized = memo(callback);
292
- return () => { var _a; return (_a = supportsFlags[supportsFlag]) !== null && _a !== void 0 ? _a : memoized(); };
252
+ return () => supportsFlags[supportsFlag] ?? memoized();
293
253
  }
294
254
 
295
255
  const supportsLinearEasing = /*@__PURE__*/ memoSupports(() => {
@@ -310,12 +270,13 @@ resolution = 10 // as milliseconds
310
270
  let points = "";
311
271
  const numPoints = Math.max(Math.round(duration / resolution), 2);
312
272
  for (let i = 0; i < numPoints; i++) {
313
- points += easing(progress(0, numPoints - 1, i)) + ", ";
273
+ points += easing(i / (numPoints - 1)) + ", ";
314
274
  }
315
275
  return `linear(${points.substring(0, points.length - 2)})`;
316
276
  };
317
277
 
318
278
  const cubicBezierAsString = ([a, b, c, d]) => `cubic-bezier(${a}, ${b}, ${c}, ${d})`;
279
+
319
280
  const supportedWaapiEasing = {
320
281
  linear: "linear",
321
282
  ease: "ease",
@@ -327,6 +288,7 @@ const supportedWaapiEasing = {
327
288
  backIn: /*@__PURE__*/ cubicBezierAsString([0.31, 0.01, 0.66, -0.59]),
328
289
  backOut: /*@__PURE__*/ cubicBezierAsString([0.33, 1.53, 0.69, 0.99]),
329
290
  };
291
+
330
292
  function mapEasingToNativeEasing(easing, duration) {
331
293
  if (!easing) {
332
294
  return undefined;
@@ -346,22 +308,244 @@ function mapEasingToNativeEasing(easing, duration) {
346
308
  }
347
309
  }
348
310
 
311
+ function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duration = 300, repeat = 0, repeatType = "loop", ease = "easeInOut", times, } = {}, pseudoElement = undefined) {
312
+ const keyframeOptions = {
313
+ [valueName]: keyframes,
314
+ };
315
+ if (times)
316
+ keyframeOptions.offset = times;
317
+ const easing = mapEasingToNativeEasing(ease, duration);
318
+ /**
319
+ * If this is an easing array, apply to keyframes, not animation as a whole
320
+ */
321
+ if (Array.isArray(easing))
322
+ keyframeOptions.easing = easing;
323
+ const animation = element.animate(keyframeOptions, {
324
+ delay,
325
+ duration,
326
+ easing: !Array.isArray(easing) ? easing : "linear",
327
+ fill: "both",
328
+ iterations: repeat + 1,
329
+ direction: repeatType === "reverse" ? "alternate" : "normal",
330
+ pseudoElement,
331
+ });
332
+ return animation;
333
+ }
334
+
335
+ function isGenerator(type) {
336
+ return typeof type === "function" && "applyToOptions" in type;
337
+ }
338
+
339
+ function applyGeneratorOptions({ type, ...options }) {
340
+ if (isGenerator(type)) {
341
+ return type.applyToOptions(options);
342
+ }
343
+ else {
344
+ options.duration ?? (options.duration = 300);
345
+ options.ease ?? (options.ease = "easeOut");
346
+ }
347
+ return options;
348
+ }
349
+
350
+ const animationMaps = new WeakMap();
351
+ const animationMapKey = (name, pseudoElement) => `${name}:${pseudoElement}`;
352
+ function getAnimationMap(element) {
353
+ const map = animationMaps.get(element) || new Map();
354
+ animationMaps.set(element, map);
355
+ return map;
356
+ }
357
+ /**
358
+ * NativeAnimation implements AnimationPlaybackControls for the browser's Web Animations API.
359
+ */
360
+ class NativeAnimation {
361
+ constructor(options) {
362
+ /**
363
+ * If we already have an animation, we don't need to instantiate one
364
+ * and can just use this as a controls interface.
365
+ */
366
+ if ("animation" in options) {
367
+ this.animation = options.animation;
368
+ return;
369
+ }
370
+ const { element, name, keyframes: unresolvedKeyframes, pseudoElement, allowFlatten = false, } = options;
371
+ let { transition } = options;
372
+ this.allowFlatten = allowFlatten;
373
+ /**
374
+ * Stop any existing animations on the element before reading existing keyframes.
375
+ *
376
+ * TODO: Check for VisualElement before using animation state. This is a fallback
377
+ * for mini animate(). Do this when implementing NativeAnimationExtended.
378
+ */
379
+ const animationMap = getAnimationMap(element);
380
+ const key = animationMapKey(name, pseudoElement || "");
381
+ const currentAnimation = animationMap.get(key);
382
+ currentAnimation && currentAnimation.stop();
383
+ /**
384
+ * TODO: If these keyframes aren't correctly hydrated then we want to throw
385
+ * run an instant animation.
386
+ */
387
+ const keyframes = hydrateKeyframes(element, name, unresolvedKeyframes, pseudoElement);
388
+ invariant(typeof transition.type !== "string", `animateMini doesn't support "type" as a string. Did you mean to import { spring } from "motion"?`);
389
+ transition = applyGeneratorOptions(transition);
390
+ this.animation = startWaapiAnimation(element, name, keyframes, transition, pseudoElement);
391
+ if (transition.autoplay === false) {
392
+ this.animation.pause();
393
+ }
394
+ this.removeAnimation = () => animationMap.delete(key);
395
+ this.animation.onfinish = () => {
396
+ if (!pseudoElement) {
397
+ style.set(element, name, getFinalKeyframe(keyframes, transition));
398
+ }
399
+ else {
400
+ this.commitStyles();
401
+ }
402
+ this.cancel();
403
+ };
404
+ /**
405
+ * TODO: Check for VisualElement before using animation state.
406
+ */
407
+ animationMap.set(key, this);
408
+ }
409
+ play() {
410
+ this.animation.play();
411
+ }
412
+ pause() {
413
+ this.animation.pause();
414
+ }
415
+ complete() {
416
+ this.animation.finish();
417
+ }
418
+ cancel() {
419
+ try {
420
+ this.animation.cancel();
421
+ }
422
+ catch (e) { }
423
+ this.removeAnimation();
424
+ }
425
+ stop() {
426
+ const { state } = this;
427
+ if (state === "idle" || state === "finished") {
428
+ return;
429
+ }
430
+ this.commitStyles();
431
+ this.cancel();
432
+ }
433
+ /**
434
+ * WAAPI doesn't natively have any interruption capabilities.
435
+ *
436
+ * In this method, we commit styles back to the DOM before cancelling
437
+ * the animation.
438
+ *
439
+ * This is designed to be overridden by NativeAnimationExtended, which
440
+ * will create a renderless JS animation and sample it twice to calculate
441
+ * its current value, "previous" value, and therefore allow
442
+ * Motion to also correctly calculate velocity for any subsequent animation
443
+ * while deferring the commit until the next animation frame.
444
+ */
445
+ commitStyles() {
446
+ this.animation.commitStyles?.();
447
+ }
448
+ get duration() {
449
+ console.log(this.animation.effect?.getComputedTiming());
450
+ const duration = this.animation.effect?.getComputedTiming().duration || 0;
451
+ return millisecondsToSeconds(Number(duration));
452
+ }
453
+ get time() {
454
+ return millisecondsToSeconds(Number(this.animation.currentTime) || 0);
455
+ }
456
+ set time(newTime) {
457
+ this.animation.currentTime = secondsToMilliseconds(newTime);
458
+ }
459
+ /**
460
+ * The playback speed of the animation.
461
+ * 1 = normal speed, 2 = double speed, 0.5 = half speed.
462
+ */
463
+ get speed() {
464
+ return this.animation.playbackRate;
465
+ }
466
+ set speed(newSpeed) {
467
+ this.animation.playbackRate = newSpeed;
468
+ }
469
+ get state() {
470
+ return this.animation.playState;
471
+ }
472
+ get startTime() {
473
+ return Number(this.animation.startTime);
474
+ }
475
+ get finished() {
476
+ return this.animation.finished;
477
+ }
478
+ flatten() {
479
+ if (this.allowFlatten) {
480
+ this.animation.effect?.updateTiming({ easing: "linear" });
481
+ }
482
+ }
483
+ /**
484
+ * Attaches a timeline to the animation, for instance the `ScrollTimeline`.
485
+ */
486
+ attachTimeline(timeline) {
487
+ this.animation.timeline = timeline;
488
+ this.animation.onfinish = null;
489
+ return noop;
490
+ }
491
+ /**
492
+ * Allows the animation to be awaited.
493
+ *
494
+ * @deprecated Use `finished` instead.
495
+ */
496
+ then(onResolve, onReject) {
497
+ return this.finished.then(onResolve).catch(onReject);
498
+ }
499
+ }
500
+
501
+ function getValueTransition$1(transition, key) {
502
+ return (transition?.[key] ??
503
+ transition?.["default"] ??
504
+ transition);
505
+ }
506
+
507
+ /**
508
+ * Implement a practical max duration for keyframe generation
509
+ * to prevent infinite loops
510
+ */
511
+ const maxGeneratorDuration = 20000;
512
+ function calcGeneratorDuration(generator) {
513
+ let duration = 0;
514
+ const timeStep = 50;
515
+ let state = generator.next(duration);
516
+ while (!state.done && duration < maxGeneratorDuration) {
517
+ duration += timeStep;
518
+ state = generator.next(duration);
519
+ }
520
+ return duration >= maxGeneratorDuration ? Infinity : duration;
521
+ }
522
+
523
+ /**
524
+ * Create a progress => progress easing function from a generator.
525
+ */
526
+ function createGeneratorEasing(options, scale = 100, createGenerator) {
527
+ const generator = createGenerator({ ...options, keyframes: [0, scale] });
528
+ const duration = Math.min(calcGeneratorDuration(generator), maxGeneratorDuration);
529
+ return {
530
+ type: "keyframes",
531
+ ease: (progress) => {
532
+ return generator.next(duration * progress).value / scale;
533
+ },
534
+ duration: millisecondsToSeconds(duration),
535
+ };
536
+ }
537
+
349
538
  function resolveElements(elementOrSelector, scope, selectorCache) {
350
- var _a;
351
539
  if (elementOrSelector instanceof EventTarget) {
352
540
  return [elementOrSelector];
353
541
  }
354
542
  else if (typeof elementOrSelector === "string") {
355
543
  let root = document;
356
544
  if (scope) {
357
- // TODO: Refactor to utils package
358
- // invariant(
359
- // Boolean(scope.current),
360
- // "Scope provided, but no element detected."
361
- // )
362
545
  root = scope.current;
363
546
  }
364
- const elements = (_a = selectorCache === null || selectorCache === void 0 ? void 0 : selectorCache[elementOrSelector]) !== null && _a !== void 0 ? _a : root.querySelectorAll(elementOrSelector);
547
+ const elements = selectorCache?.[elementOrSelector] ??
548
+ root.querySelectorAll(elementOrSelector);
365
549
  return elements ? Array.from(elements) : [];
366
550
  }
367
551
  return Array.from(elementOrSelector);
@@ -449,7 +633,6 @@ function calculateRepeatDuration(duration, repeat, _repeatDelay) {
449
633
  * calculate an absolute time for the next keyframes.
450
634
  */
451
635
  function calcNextTime(current, next, prev, labels) {
452
- var _a;
453
636
  if (typeof next === "number") {
454
637
  return next;
455
638
  }
@@ -460,7 +643,7 @@ function calcNextTime(current, next, prev, labels) {
460
643
  return prev;
461
644
  }
462
645
  else {
463
- return (_a = labels.get(next)) !== null && _a !== void 0 ? _a : current;
646
+ return labels.get(next) ?? current;
464
647
  }
465
648
  }
466
649
 
@@ -573,7 +756,7 @@ function createAnimationsFromSequence(sequence, { defaultTransition = {}, ...seq
573
756
  const numKeyframes = valueKeyframesAsList.length;
574
757
  const createGenerator = isGenerator(type)
575
758
  ? type
576
- : generators === null || generators === void 0 ? void 0 : generators[type];
759
+ : generators?.[type];
577
760
  if (numKeyframes <= 2 && createGenerator) {
578
761
  /**
579
762
  * As we're creating an easing function from a spring,
@@ -595,7 +778,7 @@ function createAnimationsFromSequence(sequence, { defaultTransition = {}, ...seq
595
778
  ease = springEasing.ease;
596
779
  duration = springEasing.duration;
597
780
  }
598
- duration !== null && duration !== void 0 ? duration : (duration = defaultDuration);
781
+ duration ?? (duration = defaultDuration);
599
782
  const startTime = currentTime + calculatedDelay;
600
783
  /**
601
784
  * If there's only one time offset of 0, fill in a second with length 1
@@ -754,204 +937,6 @@ function getValueTransition(transition, key) {
754
937
  const isNumber = (keyframe) => typeof keyframe === "number";
755
938
  const isNumberKeyframesArray = (keyframes) => keyframes.every(isNumber);
756
939
 
757
- function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duration = 300, repeat = 0, repeatType = "loop", ease = "easeInOut", times, } = {}) {
758
- const keyframeOptions = { [valueName]: keyframes };
759
- if (times)
760
- keyframeOptions.offset = times;
761
- const easing = mapEasingToNativeEasing(ease, duration);
762
- /**
763
- * If this is an easing array, apply to keyframes, not animation as a whole
764
- */
765
- if (Array.isArray(easing))
766
- keyframeOptions.easing = easing;
767
- const animation = element.animate(keyframeOptions, {
768
- delay,
769
- duration,
770
- easing: !Array.isArray(easing) ? easing : "linear",
771
- fill: "both",
772
- iterations: repeat + 1,
773
- direction: repeatType === "reverse" ? "alternate" : "normal",
774
- });
775
- return animation;
776
- }
777
-
778
- const createUnitType = (unit) => ({
779
- test: (v) => typeof v === "string" && v.endsWith(unit) && v.split(" ").length === 1,
780
- parse: parseFloat,
781
- transform: (v) => `${v}${unit}`,
782
- });
783
- const px = /*@__PURE__*/ createUnitType("px");
784
-
785
- const browserNumberValueTypes = {
786
- // Border props
787
- borderWidth: px,
788
- borderTopWidth: px,
789
- borderRightWidth: px,
790
- borderBottomWidth: px,
791
- borderLeftWidth: px,
792
- borderRadius: px,
793
- radius: px,
794
- borderTopLeftRadius: px,
795
- borderTopRightRadius: px,
796
- borderBottomRightRadius: px,
797
- borderBottomLeftRadius: px,
798
- // Positioning props
799
- width: px,
800
- maxWidth: px,
801
- height: px,
802
- maxHeight: px,
803
- top: px,
804
- right: px,
805
- bottom: px,
806
- left: px,
807
- // Spacing props
808
- padding: px,
809
- paddingTop: px,
810
- paddingRight: px,
811
- paddingBottom: px,
812
- paddingLeft: px,
813
- margin: px,
814
- marginTop: px,
815
- marginRight: px,
816
- marginBottom: px,
817
- marginLeft: px,
818
- // Misc
819
- backgroundPositionX: px,
820
- backgroundPositionY: px,
821
- };
822
-
823
- const isNotNull = (value) => value !== null;
824
- function getFinalKeyframe(keyframes, { repeat, repeatType = "loop" }, finalKeyframe) {
825
- const resolvedKeyframes = keyframes.filter(isNotNull);
826
- const index = repeat && repeatType !== "loop" && repeat % 2 === 1
827
- ? 0
828
- : resolvedKeyframes.length - 1;
829
- return !index || finalKeyframe === undefined
830
- ? resolvedKeyframes[index]
831
- : finalKeyframe;
832
- }
833
-
834
- function setCSSVar(element, name, value) {
835
- element.style.setProperty(name, value);
836
- }
837
- function setStyle(element, name, value) {
838
- element.style[name] = value;
839
- }
840
-
841
- const supportsPartialKeyframes = /*@__PURE__*/ memo(() => {
842
- try {
843
- document.createElement("div").animate({ opacity: [1] });
844
- }
845
- catch (e) {
846
- return false;
847
- }
848
- return true;
849
- });
850
-
851
- const supportsWaapi = /*@__PURE__*/ memo(() => Object.hasOwnProperty.call(Element.prototype, "animate"));
852
-
853
- const state = new WeakMap();
854
- function hydrateKeyframes(valueName, keyframes, read) {
855
- for (let i = 0; i < keyframes.length; i++) {
856
- if (keyframes[i] === null) {
857
- keyframes[i] = i === 0 ? read() : keyframes[i - 1];
858
- }
859
- if (typeof keyframes[i] === "number" &&
860
- browserNumberValueTypes[valueName]) {
861
- keyframes[i] = browserNumberValueTypes[valueName].transform(keyframes[i]);
862
- }
863
- }
864
- if (!supportsPartialKeyframes() && keyframes.length < 2) {
865
- keyframes.unshift(read());
866
- }
867
- }
868
- const defaultEasing = "easeOut";
869
- function getElementAnimationState(element) {
870
- const animationState = state.get(element) || new Map();
871
- state.set(element, animationState);
872
- return state.get(element);
873
- }
874
- class NativeAnimation extends NativeAnimationControls {
875
- constructor(element, valueName, valueKeyframes, options) {
876
- const isCSSVar = valueName.startsWith("--");
877
- invariant(typeof options.type !== "string", `animateMini doesn't support "type" as a string. Did you mean to import { spring } from "framer-motion"?`);
878
- const existingAnimation = getElementAnimationState(element).get(valueName);
879
- existingAnimation && existingAnimation.stop();
880
- const readInitialKeyframe = () => {
881
- return valueName.startsWith("--")
882
- ? element.style.getPropertyValue(valueName)
883
- : window.getComputedStyle(element)[valueName];
884
- };
885
- if (!Array.isArray(valueKeyframes)) {
886
- valueKeyframes = [valueKeyframes];
887
- }
888
- hydrateKeyframes(valueName, valueKeyframes, readInitialKeyframe);
889
- // TODO: Replace this with toString()?
890
- if (isGenerator(options.type)) {
891
- const generatorOptions = createGeneratorEasing(options, 100, options.type);
892
- options.ease = supportsLinearEasing()
893
- ? generatorOptions.ease
894
- : defaultEasing;
895
- options.duration = secondsToMilliseconds(generatorOptions.duration);
896
- options.type = "keyframes";
897
- }
898
- else {
899
- options.ease = options.ease || defaultEasing;
900
- }
901
- const onFinish = () => {
902
- this.setValue(element, valueName, getFinalKeyframe(valueKeyframes, options));
903
- this.cancel();
904
- this.resolveFinishedPromise();
905
- };
906
- const init = () => {
907
- this.setValue = isCSSVar ? setCSSVar : setStyle;
908
- this.options = options;
909
- this.updateFinishedPromise();
910
- this.removeAnimation = () => {
911
- const elementState = state.get(element);
912
- elementState && elementState.delete(valueName);
913
- };
914
- };
915
- if (!supportsWaapi()) {
916
- super();
917
- init();
918
- onFinish();
919
- }
920
- else {
921
- super(startWaapiAnimation(element, valueName, valueKeyframes, options));
922
- init();
923
- if (options.autoplay === false) {
924
- this.animation.pause();
925
- }
926
- this.animation.onfinish = onFinish;
927
- getElementAnimationState(element).set(valueName, this);
928
- }
929
- }
930
- /**
931
- * Allows the returned animation to be awaited or promise-chained. Currently
932
- * resolves when the animation finishes at all but in a future update could/should
933
- * reject if its cancels.
934
- */
935
- then(resolve, reject) {
936
- return this.currentFinishedPromise.then(resolve, reject);
937
- }
938
- updateFinishedPromise() {
939
- this.currentFinishedPromise = new Promise((resolve) => {
940
- this.resolveFinishedPromise = resolve;
941
- });
942
- }
943
- play() {
944
- if (this.state === "finished") {
945
- this.updateFinishedPromise();
946
- }
947
- super.play();
948
- }
949
- cancel() {
950
- this.removeAnimation();
951
- super.cancel();
952
- }
953
- }
954
-
955
940
  function animateElements(elementOrSelector, keyframes, options, scope) {
956
941
  const elements = resolveElements(elementOrSelector, scope);
957
942
  const numElements = elements.length;
@@ -971,13 +956,15 @@ function animateElements(elementOrSelector, keyframes, options, scope) {
971
956
  const valueOptions = {
972
957
  ...getValueTransition$1(elementTransition, valueName),
973
958
  };
974
- valueOptions.duration = valueOptions.duration
975
- ? secondsToMilliseconds(valueOptions.duration)
976
- : valueOptions.duration;
977
- valueOptions.delay = secondsToMilliseconds(valueOptions.delay || 0);
978
- valueOptions.allowFlatten =
979
- !elementTransition.type && !elementTransition.ease;
980
- animations.push(new NativeAnimation(element, valueName, valueKeyframes, valueOptions));
959
+ valueOptions.duration && (valueOptions.duration = secondsToMilliseconds(valueOptions.duration));
960
+ valueOptions.delay && (valueOptions.delay = secondsToMilliseconds(valueOptions.delay));
961
+ animations.push(new NativeAnimation({
962
+ element,
963
+ name: valueName,
964
+ keyframes: valueKeyframes,
965
+ transition: valueOptions,
966
+ allowFlatten: !elementTransition.type && !elementTransition.ease,
967
+ }));
981
968
  }
982
969
  }
983
970
  return animations;
@@ -988,12 +975,12 @@ function animateSequence(definition, options) {
988
975
  createAnimationsFromSequence(definition, options).forEach(({ keyframes, transition }, element) => {
989
976
  animations.push(...animateElements(element, keyframes, transition));
990
977
  });
991
- return new GroupPlaybackControls(animations);
978
+ return new GroupAnimationWithThen(animations);
992
979
  }
993
980
 
994
981
  const createScopedWaapiAnimate = (scope) => {
995
982
  function scopedAnimate(elementOrSelector, keyframes, options) {
996
- return new GroupPlaybackControls(animateElements(elementOrSelector, keyframes, options, scope));
983
+ return new GroupAnimationWithThen(animateElements(elementOrSelector, keyframes, options, scope));
997
984
  }
998
985
  return scopedAnimate;
999
986
  };