motion 12.6.3-alpha.0 → 12.6.4-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.
Files changed (77) hide show
  1. package/dist/cjs/debug.js +18 -14
  2. package/dist/cjs/index.js +414 -359
  3. package/dist/cjs/mini.js +339 -352
  4. package/dist/cjs/react-client.js +180 -188
  5. package/dist/cjs/react-m.js +24 -24
  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/interpolate.mjs +2 -1
  40. package/dist/es/framer-motion/dist/es/utils/mix/complex.mjs +1 -2
  41. package/dist/es/framer-motion/dist/es/value/types/complex/index.mjs +2 -3
  42. package/dist/es/framer-motion/dist/es/value/use-scroll.mjs +2 -2
  43. package/dist/es/framer-motion/dist/es/value/use-will-change/add-will-change.mjs +0 -7
  44. package/dist/es/motion/lib/index.mjs +1 -0
  45. package/dist/es/motion/lib/react.mjs +1 -1
  46. package/dist/es/motion-dom/dist/es/animation/{controls/BaseGroup.mjs → GroupAnimation.mjs} +4 -5
  47. package/dist/es/motion-dom/dist/es/animation/GroupAnimationWithThen.mjs +9 -0
  48. package/dist/es/motion-dom/dist/es/animation/NativeAnimation.mjs +161 -0
  49. package/dist/es/motion-dom/dist/es/animation/generators/utils/is-generator.mjs +1 -1
  50. package/dist/es/motion-dom/dist/es/animation/keyframes/get-final.mjs +12 -0
  51. package/dist/es/motion-dom/dist/es/animation/keyframes/hydrate.mjs +26 -0
  52. package/dist/es/motion-dom/dist/es/animation/utils/get-value-transition.mjs +3 -5
  53. package/dist/es/motion-dom/dist/es/animation/waapi/easing/cubic-bezier.mjs +3 -0
  54. package/dist/es/motion-dom/dist/es/animation/waapi/easing/is-supported.mjs +14 -0
  55. package/dist/es/motion-dom/dist/es/animation/waapi/easing/map-easing.mjs +26 -0
  56. package/dist/es/motion-dom/dist/es/animation/waapi/easing/supported.mjs +15 -0
  57. package/dist/es/{framer-motion/dist/es/animation/animators/waapi/index.mjs → motion-dom/dist/es/animation/waapi/start-waapi-animation.mjs} +8 -6
  58. 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
  59. package/dist/es/motion-dom/dist/es/animation/waapi/utils/apply-generator.mjs +14 -0
  60. package/dist/es/motion-dom/dist/es/animation/waapi/utils/linear.mjs +1 -4
  61. package/dist/es/motion-dom/dist/es/animation/waapi/utils/px-values.mjs +39 -0
  62. package/dist/es/motion-dom/dist/es/gestures/press/index.mjs +1 -1
  63. package/dist/es/motion-dom/dist/es/render/dom/style.mjs +15 -0
  64. package/dist/es/motion-dom/dist/es/utils/resolve-elements.mjs +2 -7
  65. package/dist/es/motion-dom/dist/es/utils/supports/flags.mjs +1 -3
  66. package/dist/es/motion-dom/dist/es/utils/supports/memo.mjs +1 -1
  67. package/dist/es/motion-dom/dist/es/value/index.mjs +1 -1
  68. package/dist/es/motion-utils/dist/es/errors.mjs +2 -4
  69. package/dist/es/motion-utils/dist/es/global-config.mjs +1 -4
  70. package/dist/motion.dev.js +414 -359
  71. package/dist/motion.js +1 -1
  72. package/package.json +3 -3
  73. package/dist/es/framer-motion/dist/es/animation/animators/waapi/NativeAnimation.mjs +0 -116
  74. package/dist/es/framer-motion/dist/es/animation/animators/waapi/utils/style.mjs +0 -8
  75. package/dist/es/motion-dom/dist/es/animation/controls/Group.mjs +0 -13
  76. package/dist/es/motion-dom/dist/es/animation/waapi/NativeAnimationControls.mjs +0 -85
  77. package/dist/es/motion-dom/dist/es/animation/waapi/utils/easing.mjs +0 -44
@@ -23,10 +23,7 @@ function useUnmountEffect(callback) {
23
23
  return react.useEffect(() => () => callback(), []);
24
24
  }
25
25
 
26
- /*#__NO_SIDE_EFFECTS__*/
27
- const noop = (any) => any;
28
-
29
- let invariant = noop;
26
+ let invariant = () => { };
30
27
  if (process.env.NODE_ENV !== "production") {
31
28
  invariant = (check, message) => {
32
29
  if (!check) {
@@ -45,23 +42,8 @@ function memo(callback) {
45
42
  };
46
43
  }
47
44
 
48
- /*
49
- Progress within given range
50
-
51
- Given a lower limit and an upper limit, we return the progress
52
- (expressed as a number 0-1) represented by the given value, and
53
- limit that progress to within 0-1.
54
-
55
- @param [number]: Lower limit
56
- @param [number]: Upper limit
57
- @param [number]: Value to find progress within given range
58
- @return [number]: Progress of value within range as expressed 0-1
59
- */
60
45
  /*#__NO_SIDE_EFFECTS__*/
61
- const progress = (from, to, value) => {
62
- const toFromDifference = to - from;
63
- return toFromDifference === 0 ? 1 : (value - from) / toFromDifference;
64
- };
46
+ const noop = (any) => any;
65
47
 
66
48
  /**
67
49
  * Converts seconds to milliseconds
@@ -76,15 +58,14 @@ const millisecondsToSeconds = (milliseconds) => milliseconds / 1000;
76
58
 
77
59
  const supportsScrollTimeline = /* @__PURE__ */ memo(() => window.ScrollTimeline !== undefined);
78
60
 
79
- class BaseGroupPlaybackControls {
61
+ class GroupAnimation {
80
62
  constructor(animations) {
81
63
  // Bound to accomodate common `return animation.stop` pattern
82
64
  this.stop = () => this.runAll("stop");
83
65
  this.animations = animations.filter(Boolean);
84
66
  }
85
67
  get finished() {
86
- // Support for new finished Promise and legacy thennable API
87
- return Promise.all(this.animations.map((animation) => "finished" in animation ? animation.finished : animation));
68
+ return Promise.all(this.animations.map((animation) => animation.finished));
88
69
  }
89
70
  /**
90
71
  * TODO: Filter out cancelled or stopped animations before returning
@@ -155,141 +136,104 @@ class BaseGroupPlaybackControls {
155
136
  }
156
137
  }
157
138
 
158
- /**
159
- * TODO: This is a temporary class to support the legacy
160
- * thennable API
161
- */
162
- class GroupPlaybackControls extends BaseGroupPlaybackControls {
163
- then(onResolve, onReject) {
164
- return Promise.all(this.animations).then(onResolve).catch(onReject);
139
+ class GroupAnimationWithThen extends GroupAnimation {
140
+ then(onResolve, _onReject) {
141
+ return this.finished.finally(onResolve).then(() => { });
165
142
  }
166
143
  }
167
144
 
168
- function getValueTransition(transition, key) {
169
- return transition
170
- ? transition[key] ||
171
- transition["default"] ||
172
- transition
173
- : undefined;
174
- }
175
-
176
- /**
177
- * Implement a practical max duration for keyframe generation
178
- * to prevent infinite loops
179
- */
180
- const maxGeneratorDuration = 20000;
181
- function calcGeneratorDuration(generator) {
182
- let duration = 0;
183
- const timeStep = 50;
184
- let state = generator.next(duration);
185
- while (!state.done && duration < maxGeneratorDuration) {
186
- duration += timeStep;
187
- state = generator.next(duration);
188
- }
189
- return duration >= maxGeneratorDuration ? Infinity : duration;
190
- }
191
-
192
- /**
193
- * Create a progress => progress easing function from a generator.
194
- */
195
- function createGeneratorEasing(options, scale = 100, createGenerator) {
196
- const generator = createGenerator({ ...options, keyframes: [0, scale] });
197
- const duration = Math.min(calcGeneratorDuration(generator), maxGeneratorDuration);
198
- return {
199
- type: "keyframes",
200
- ease: (progress) => {
201
- return generator.next(duration * progress).value / scale;
202
- },
203
- duration: millisecondsToSeconds(duration),
204
- };
205
- }
206
-
207
- function isGenerator(type) {
208
- return typeof type === "function";
209
- }
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
+ },
157
+ };
210
158
 
211
- function attachTimeline(animation, timeline) {
212
- animation.timeline = timeline;
213
- animation.onfinish = null;
159
+ const isNotNull = (value) => value !== null;
160
+ function getFinalKeyframe(keyframes, { repeat, repeatType = "loop" }, finalKeyframe) {
161
+ const resolvedKeyframes = keyframes.filter(isNotNull);
162
+ const index = repeat && repeatType !== "loop" && repeat % 2 === 1
163
+ ? 0
164
+ : resolvedKeyframes.length - 1;
165
+ return !index || finalKeyframe === undefined
166
+ ? resolvedKeyframes[index]
167
+ : finalKeyframe;
214
168
  }
215
169
 
216
- class NativeAnimationControls {
217
- constructor(animation) {
218
- this.animation = animation;
219
- }
220
- get duration() {
221
- var _a, _b, _c;
222
- const durationInMs = ((_b = (_a = this.animation) === null || _a === void 0 ? void 0 : _a.effect) === null || _b === void 0 ? void 0 : _b.getComputedTiming().duration) ||
223
- ((_c = this.options) === null || _c === void 0 ? void 0 : _c.duration) ||
224
- 300;
225
- return millisecondsToSeconds(Number(durationInMs));
226
- }
227
- get time() {
228
- var _a;
229
- if (this.animation) {
230
- return millisecondsToSeconds(((_a = this.animation) === null || _a === void 0 ? void 0 : _a.currentTime) || 0);
231
- }
232
- return 0;
233
- }
234
- set time(newTime) {
235
- if (this.animation) {
236
- this.animation.currentTime = secondsToMilliseconds(newTime);
237
- }
238
- }
239
- get speed() {
240
- return this.animation ? this.animation.playbackRate : 1;
241
- }
242
- set speed(newSpeed) {
243
- if (this.animation) {
244
- this.animation.playbackRate = newSpeed;
245
- }
246
- }
247
- get state() {
248
- return this.animation ? this.animation.playState : "finished";
249
- }
250
- get startTime() {
251
- return this.animation ? this.animation.startTime : null;
252
- }
253
- get finished() {
254
- return this.animation ? this.animation.finished : Promise.resolve();
170
+ const supportsPartialKeyframes = /*@__PURE__*/ memo(() => {
171
+ try {
172
+ document.createElement("div").animate({ opacity: [1] });
255
173
  }
256
- play() {
257
- this.animation && this.animation.play();
174
+ catch (e) {
175
+ return false;
258
176
  }
259
- pause() {
260
- this.animation && this.animation.pause();
177
+ return true;
178
+ });
179
+
180
+ const pxValues = new Set([
181
+ // Border props
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];
261
221
  }
262
- stop() {
263
- if (!this.animation ||
264
- this.state === "idle" ||
265
- this.state === "finished") {
266
- return;
222
+ for (let i = 0; i < keyframes.length; i++) {
223
+ if (keyframes[i] === null) {
224
+ keyframes[i] =
225
+ i === 0 && !pseudoElement
226
+ ? style.get(element, name)
227
+ : keyframes[i - 1];
267
228
  }
268
- if (this.animation.commitStyles) {
269
- this.animation.commitStyles();
229
+ if (typeof keyframes[i] === "number" && pxValues.has(name)) {
230
+ keyframes[i] = keyframes[i] + "px";
270
231
  }
271
- this.cancel();
272
- }
273
- flatten() {
274
- var _a, _b;
275
- if (!this.animation || !((_a = this.options) === null || _a === void 0 ? void 0 : _a.allowFlatten))
276
- return;
277
- (_b = this.animation.effect) === null || _b === void 0 ? void 0 : _b.updateTiming({ easing: "linear" });
278
- }
279
- attachTimeline(timeline) {
280
- if (this.animation)
281
- attachTimeline(this.animation, timeline);
282
- return noop;
283
232
  }
284
- complete() {
285
- this.animation && this.animation.finish();
286
- }
287
- cancel() {
288
- try {
289
- this.animation && this.animation.cancel();
290
- }
291
- catch (e) { }
233
+ if (!pseudoElement && !supportsPartialKeyframes() && keyframes.length < 2) {
234
+ keyframes.unshift(style.get(element, name));
292
235
  }
236
+ return keyframes;
293
237
  }
294
238
 
295
239
  const isBezierDefinition = (easing) => Array.isArray(easing) && typeof easing[0] === "number";
@@ -298,13 +242,11 @@ const isBezierDefinition = (easing) => Array.isArray(easing) && typeof easing[0]
298
242
  * Add the ability for test suites to manually set support flags
299
243
  * to better test more environments.
300
244
  */
301
- const supportsFlags = {
302
- linearEasing: undefined,
303
- };
245
+ const supportsFlags = {};
304
246
 
305
247
  function memoSupports(callback, supportsFlag) {
306
248
  const memoized = memo(callback);
307
- return () => { var _a; return (_a = supportsFlags[supportsFlag]) !== null && _a !== void 0 ? _a : memoized(); };
249
+ return () => supportsFlags[supportsFlag] ?? memoized();
308
250
  }
309
251
 
310
252
  const supportsLinearEasing = /*@__PURE__*/ memoSupports(() => {
@@ -325,12 +267,13 @@ resolution = 10 // as milliseconds
325
267
  let points = "";
326
268
  const numPoints = Math.max(Math.round(duration / resolution), 2);
327
269
  for (let i = 0; i < numPoints; i++) {
328
- points += easing(progress(0, numPoints - 1, i)) + ", ";
270
+ points += easing(i / (numPoints - 1)) + ", ";
329
271
  }
330
272
  return `linear(${points.substring(0, points.length - 2)})`;
331
273
  };
332
274
 
333
275
  const cubicBezierAsString = ([a, b, c, d]) => `cubic-bezier(${a}, ${b}, ${c}, ${d})`;
276
+
334
277
  const supportedWaapiEasing = {
335
278
  linear: "linear",
336
279
  ease: "ease",
@@ -342,6 +285,7 @@ const supportedWaapiEasing = {
342
285
  backIn: /*@__PURE__*/ cubicBezierAsString([0.31, 0.01, 0.66, -0.59]),
343
286
  backOut: /*@__PURE__*/ cubicBezierAsString([0.33, 1.53, 0.69, 0.99]),
344
287
  };
288
+
345
289
  function mapEasingToNativeEasing(easing, duration) {
346
290
  if (!easing) {
347
291
  return undefined;
@@ -361,29 +305,10 @@ function mapEasingToNativeEasing(easing, duration) {
361
305
  }
362
306
  }
363
307
 
364
- function resolveElements(elementOrSelector, scope, selectorCache) {
365
- var _a;
366
- if (elementOrSelector instanceof EventTarget) {
367
- return [elementOrSelector];
368
- }
369
- else if (typeof elementOrSelector === "string") {
370
- let root = document;
371
- if (scope) {
372
- // TODO: Refactor to utils package
373
- // invariant(
374
- // Boolean(scope.current),
375
- // "Scope provided, but no element detected."
376
- // )
377
- root = scope.current;
378
- }
379
- const elements = (_a = selectorCache === null || selectorCache === void 0 ? void 0 : selectorCache[elementOrSelector]) !== null && _a !== void 0 ? _a : root.querySelectorAll(elementOrSelector);
380
- return elements ? Array.from(elements) : [];
381
- }
382
- return Array.from(elementOrSelector);
383
- }
384
-
385
- function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duration = 300, repeat = 0, repeatType = "loop", ease = "easeInOut", times, } = {}) {
386
- const keyframeOptions = { [valueName]: keyframes };
308
+ function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duration = 300, repeat = 0, repeatType = "loop", ease = "easeInOut", times, } = {}, pseudoElement = undefined) {
309
+ const keyframeOptions = {
310
+ [valueName]: keyframes,
311
+ };
387
312
  if (times)
388
313
  keyframeOptions.offset = times;
389
314
  const easing = mapEasingToNativeEasing(ease, duration);
@@ -399,187 +324,199 @@ function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duratio
399
324
  fill: "both",
400
325
  iterations: repeat + 1,
401
326
  direction: repeatType === "reverse" ? "alternate" : "normal",
327
+ pseudoElement,
402
328
  });
403
329
  return animation;
404
330
  }
405
331
 
406
- const createUnitType = (unit) => ({
407
- test: (v) => typeof v === "string" && v.endsWith(unit) && v.split(" ").length === 1,
408
- parse: parseFloat,
409
- transform: (v) => `${v}${unit}`,
410
- });
411
- const px = /*@__PURE__*/ createUnitType("px");
412
-
413
- const browserNumberValueTypes = {
414
- // Border props
415
- borderWidth: px,
416
- borderTopWidth: px,
417
- borderRightWidth: px,
418
- borderBottomWidth: px,
419
- borderLeftWidth: px,
420
- borderRadius: px,
421
- radius: px,
422
- borderTopLeftRadius: px,
423
- borderTopRightRadius: px,
424
- borderBottomRightRadius: px,
425
- borderBottomLeftRadius: px,
426
- // Positioning props
427
- width: px,
428
- maxWidth: px,
429
- height: px,
430
- maxHeight: px,
431
- top: px,
432
- right: px,
433
- bottom: px,
434
- left: px,
435
- // Spacing props
436
- padding: px,
437
- paddingTop: px,
438
- paddingRight: px,
439
- paddingBottom: px,
440
- paddingLeft: px,
441
- margin: px,
442
- marginTop: px,
443
- marginRight: px,
444
- marginBottom: px,
445
- marginLeft: px,
446
- // Misc
447
- backgroundPositionX: px,
448
- backgroundPositionY: px,
449
- };
450
-
451
- const isNotNull = (value) => value !== null;
452
- function getFinalKeyframe(keyframes, { repeat, repeatType = "loop" }, finalKeyframe) {
453
- const resolvedKeyframes = keyframes.filter(isNotNull);
454
- const index = repeat && repeatType !== "loop" && repeat % 2 === 1
455
- ? 0
456
- : resolvedKeyframes.length - 1;
457
- return !index || finalKeyframe === undefined
458
- ? resolvedKeyframes[index]
459
- : finalKeyframe;
460
- }
461
-
462
- function setCSSVar(element, name, value) {
463
- element.style.setProperty(name, value);
464
- }
465
- function setStyle(element, name, value) {
466
- element.style[name] = value;
332
+ function isGenerator(type) {
333
+ return typeof type === "function" && "applyToOptions" in type;
467
334
  }
468
335
 
469
- const supportsPartialKeyframes = /*@__PURE__*/ memo(() => {
470
- try {
471
- document.createElement("div").animate({ opacity: [1] });
472
- }
473
- catch (e) {
474
- return false;
475
- }
476
- return true;
477
- });
478
-
479
- const supportsWaapi = /*@__PURE__*/ memo(() => Object.hasOwnProperty.call(Element.prototype, "animate"));
480
-
481
- const state = new WeakMap();
482
- function hydrateKeyframes(valueName, keyframes, read) {
483
- for (let i = 0; i < keyframes.length; i++) {
484
- if (keyframes[i] === null) {
485
- keyframes[i] = i === 0 ? read() : keyframes[i - 1];
486
- }
487
- if (typeof keyframes[i] === "number" &&
488
- browserNumberValueTypes[valueName]) {
489
- keyframes[i] = browserNumberValueTypes[valueName].transform(keyframes[i]);
490
- }
336
+ function applyGeneratorOptions({ type, ...options }) {
337
+ if (isGenerator(type)) {
338
+ return type.applyToOptions(options);
491
339
  }
492
- if (!supportsPartialKeyframes() && keyframes.length < 2) {
493
- keyframes.unshift(read());
340
+ else {
341
+ options.duration ?? (options.duration = 300);
342
+ options.ease ?? (options.ease = "easeOut");
494
343
  }
344
+ return options;
495
345
  }
496
- const defaultEasing = "easeOut";
497
- function getElementAnimationState(element) {
498
- const animationState = state.get(element) || new Map();
499
- state.set(element, animationState);
500
- return state.get(element);
346
+
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;
501
353
  }
502
- class NativeAnimation extends NativeAnimationControls {
503
- constructor(element, valueName, valueKeyframes, options) {
504
- const isCSSVar = valueName.startsWith("--");
505
- invariant(typeof options.type !== "string", `animateMini doesn't support "type" as a string. Did you mean to import { spring } from "framer-motion"?`);
506
- const existingAnimation = getElementAnimationState(element).get(valueName);
507
- existingAnimation && existingAnimation.stop();
508
- const readInitialKeyframe = () => {
509
- return valueName.startsWith("--")
510
- ? element.style.getPropertyValue(valueName)
511
- : window.getComputedStyle(element)[valueName];
512
- };
513
- if (!Array.isArray(valueKeyframes)) {
514
- valueKeyframes = [valueKeyframes];
515
- }
516
- hydrateKeyframes(valueName, valueKeyframes, readInitialKeyframe);
517
- // TODO: Replace this with toString()?
518
- if (isGenerator(options.type)) {
519
- const generatorOptions = createGeneratorEasing(options, 100, options.type);
520
- options.ease = supportsLinearEasing()
521
- ? generatorOptions.ease
522
- : defaultEasing;
523
- options.duration = secondsToMilliseconds(generatorOptions.duration);
524
- options.type = "keyframes";
354
+ /**
355
+ * NativeAnimation implements AnimationPlaybackControls for the browser's Web Animations API.
356
+ */
357
+ class NativeAnimation {
358
+ constructor(options) {
359
+ /**
360
+ * If we already have an animation, we don't need to instantiate one
361
+ * and can just use this as a controls interface.
362
+ */
363
+ if ("animation" in options) {
364
+ this.animation = options.animation;
365
+ return;
525
366
  }
526
- else {
527
- options.ease = options.ease || defaultEasing;
367
+ const { element, name, keyframes: unresolvedKeyframes, pseudoElement, allowFlatten = false, } = options;
368
+ let { transition } = options;
369
+ this.allowFlatten = allowFlatten;
370
+ /**
371
+ * Stop any existing animations on the element before reading existing keyframes.
372
+ *
373
+ * TODO: Check for VisualElement before using animation state. This is a fallback
374
+ * for mini animate(). Do this when implementing NativeAnimationExtended.
375
+ */
376
+ const animationMap = getAnimationMap(element);
377
+ const key = animationMapKey(name, pseudoElement || "");
378
+ const currentAnimation = animationMap.get(key);
379
+ currentAnimation && currentAnimation.stop();
380
+ /**
381
+ * TODO: If these keyframes aren't correctly hydrated then we want to throw
382
+ * run an instant animation.
383
+ */
384
+ const keyframes = hydrateKeyframes(element, name, unresolvedKeyframes, pseudoElement);
385
+ invariant(typeof transition.type !== "string", `animateMini doesn't support "type" as a string. Did you mean to import { spring } from "motion"?`);
386
+ transition = applyGeneratorOptions(transition);
387
+ this.animation = startWaapiAnimation(element, name, keyframes, transition, pseudoElement);
388
+ if (transition.autoplay === false) {
389
+ this.animation.pause();
528
390
  }
529
- const onFinish = () => {
530
- this.setValue(element, valueName, getFinalKeyframe(valueKeyframes, options));
391
+ this.removeAnimation = () => animationMap.delete(key);
392
+ this.animation.onfinish = () => {
393
+ if (!pseudoElement) {
394
+ style.set(element, name, getFinalKeyframe(keyframes, transition));
395
+ }
396
+ else {
397
+ this.commitStyles();
398
+ }
531
399
  this.cancel();
532
- this.resolveFinishedPromise();
533
- };
534
- const init = () => {
535
- this.setValue = isCSSVar ? setCSSVar : setStyle;
536
- this.options = options;
537
- this.updateFinishedPromise();
538
- this.removeAnimation = () => {
539
- const elementState = state.get(element);
540
- elementState && elementState.delete(valueName);
541
- };
542
400
  };
543
- if (!supportsWaapi()) {
544
- super();
545
- init();
546
- onFinish();
401
+ /**
402
+ * TODO: Check for VisualElement before using animation state.
403
+ */
404
+ animationMap.set(key, this);
405
+ }
406
+ play() {
407
+ this.animation.play();
408
+ }
409
+ pause() {
410
+ this.animation.pause();
411
+ }
412
+ complete() {
413
+ this.animation.finish();
414
+ }
415
+ cancel() {
416
+ try {
417
+ this.animation.cancel();
547
418
  }
548
- else {
549
- super(startWaapiAnimation(element, valueName, valueKeyframes, options));
550
- init();
551
- if (options.autoplay === false) {
552
- this.animation.pause();
553
- }
554
- this.animation.onfinish = onFinish;
555
- getElementAnimationState(element).set(valueName, this);
419
+ catch (e) { }
420
+ this.removeAnimation();
421
+ }
422
+ stop() {
423
+ const { state } = this;
424
+ if (state === "idle" || state === "finished") {
425
+ return;
556
426
  }
427
+ this.commitStyles();
428
+ this.cancel();
557
429
  }
558
430
  /**
559
- * Allows the returned animation to be awaited or promise-chained. Currently
560
- * resolves when the animation finishes at all but in a future update could/should
561
- * reject if its cancels.
431
+ * WAAPI doesn't natively have any interruption capabilities.
432
+ *
433
+ * In this method, we commit styles back to the DOM before cancelling
434
+ * the animation.
435
+ *
436
+ * This is designed to be overridden by NativeAnimationExtended, which
437
+ * will create a renderless JS animation and sample it twice to calculate
438
+ * its current value, "previous" value, and therefore allow
439
+ * Motion to also correctly calculate velocity for any subsequent animation
440
+ * while deferring the commit until the next animation frame.
562
441
  */
563
- then(resolve, reject) {
564
- return this.currentFinishedPromise.then(resolve, reject);
442
+ commitStyles() {
443
+ this.animation.commitStyles?.();
565
444
  }
566
- updateFinishedPromise() {
567
- this.currentFinishedPromise = new Promise((resolve) => {
568
- this.resolveFinishedPromise = resolve;
569
- });
445
+ get duration() {
446
+ console.log(this.animation.effect?.getComputedTiming());
447
+ const duration = this.animation.effect?.getComputedTiming().duration || 0;
448
+ return millisecondsToSeconds(Number(duration));
570
449
  }
571
- play() {
572
- if (this.state === "finished") {
573
- this.updateFinishedPromise();
450
+ get time() {
451
+ return millisecondsToSeconds(Number(this.animation.currentTime) || 0);
452
+ }
453
+ set time(newTime) {
454
+ this.animation.currentTime = secondsToMilliseconds(newTime);
455
+ }
456
+ /**
457
+ * The playback speed of the animation.
458
+ * 1 = normal speed, 2 = double speed, 0.5 = half speed.
459
+ */
460
+ get speed() {
461
+ return this.animation.playbackRate;
462
+ }
463
+ set speed(newSpeed) {
464
+ this.animation.playbackRate = newSpeed;
465
+ }
466
+ get state() {
467
+ return this.animation.playState;
468
+ }
469
+ get startTime() {
470
+ return Number(this.animation.startTime);
471
+ }
472
+ get finished() {
473
+ return this.animation.finished;
474
+ }
475
+ flatten() {
476
+ if (this.allowFlatten) {
477
+ this.animation.effect?.updateTiming({ easing: "linear" });
574
478
  }
575
- super.play();
576
479
  }
577
- cancel() {
578
- this.removeAnimation();
579
- super.cancel();
480
+ /**
481
+ * Attaches a timeline to the animation, for instance the `ScrollTimeline`.
482
+ */
483
+ attachTimeline(timeline) {
484
+ this.animation.timeline = timeline;
485
+ this.animation.onfinish = null;
486
+ return noop;
487
+ }
488
+ /**
489
+ * Allows the animation to be awaited.
490
+ *
491
+ * @deprecated Use `finished` instead.
492
+ */
493
+ then(onResolve, onReject) {
494
+ return this.finished.then(onResolve).catch(onReject);
580
495
  }
581
496
  }
582
497
 
498
+ function getValueTransition(transition, key) {
499
+ return (transition?.[key] ??
500
+ transition?.["default"] ??
501
+ transition);
502
+ }
503
+
504
+ function resolveElements(elementOrSelector, scope, selectorCache) {
505
+ if (elementOrSelector instanceof EventTarget) {
506
+ return [elementOrSelector];
507
+ }
508
+ else if (typeof elementOrSelector === "string") {
509
+ let root = document;
510
+ if (scope) {
511
+ root = scope.current;
512
+ }
513
+ const elements = selectorCache?.[elementOrSelector] ??
514
+ root.querySelectorAll(elementOrSelector);
515
+ return elements ? Array.from(elements) : [];
516
+ }
517
+ return Array.from(elementOrSelector);
518
+ }
519
+
583
520
  function animateElements(elementOrSelector, keyframes, options, scope) {
584
521
  const elements = resolveElements(elementOrSelector, scope);
585
522
  const numElements = elements.length;
@@ -599,13 +536,15 @@ function animateElements(elementOrSelector, keyframes, options, scope) {
599
536
  const valueOptions = {
600
537
  ...getValueTransition(elementTransition, valueName),
601
538
  };
602
- valueOptions.duration = valueOptions.duration
603
- ? secondsToMilliseconds(valueOptions.duration)
604
- : valueOptions.duration;
605
- valueOptions.delay = secondsToMilliseconds(valueOptions.delay || 0);
606
- valueOptions.allowFlatten =
607
- !elementTransition.type && !elementTransition.ease;
608
- animations.push(new NativeAnimation(element, valueName, valueKeyframes, valueOptions));
539
+ valueOptions.duration && (valueOptions.duration = secondsToMilliseconds(valueOptions.duration));
540
+ valueOptions.delay && (valueOptions.delay = secondsToMilliseconds(valueOptions.delay));
541
+ animations.push(new NativeAnimation({
542
+ element,
543
+ name: valueName,
544
+ keyframes: valueKeyframes,
545
+ transition: valueOptions,
546
+ allowFlatten: !elementTransition.type && !elementTransition.ease,
547
+ }));
609
548
  }
610
549
  }
611
550
  return animations;
@@ -613,7 +552,7 @@ function animateElements(elementOrSelector, keyframes, options, scope) {
613
552
 
614
553
  const createScopedWaapiAnimate = (scope) => {
615
554
  function scopedAnimate(elementOrSelector, keyframes, options) {
616
- return new GroupPlaybackControls(animateElements(elementOrSelector, keyframes, options, scope));
555
+ return new GroupAnimationWithThen(animateElements(elementOrSelector, keyframes, options, scope));
617
556
  }
618
557
  return scopedAnimate;
619
558
  };