framer-motion 12.3.1 → 12.4.1

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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var create = require('./create-CfaH3l7_.js');
5
+ var create = require('./create-C_OgoxmH.js');
6
6
  require('motion-dom');
7
7
  require('motion-utils');
8
8
  require('react/jsx-runtime');
@@ -58,7 +58,21 @@ const MotionGlobalConfig = {
58
58
  useManualTiming: false,
59
59
  };
60
60
 
61
- function createRenderStep(runNextFrame) {
61
+ const stepsOrder = [
62
+ "read", // Read
63
+ "resolveKeyframes", // Write/Read/Write/Read
64
+ "update", // Compute
65
+ "preRender", // Compute
66
+ "render", // Write
67
+ "postRender", // Compute
68
+ ];
69
+
70
+ const statsBuffer = {
71
+ value: null,
72
+ addProjectionMetrics: null,
73
+ };
74
+
75
+ function createRenderStep(runNextFrame, stepName) {
62
76
  /**
63
77
  * We create and reuse two queues, one to queue jobs for the current frame
64
78
  * and one for the next. We reuse to avoid triggering GC after x frames.
@@ -80,11 +94,13 @@ function createRenderStep(runNextFrame) {
80
94
  timestamp: 0.0,
81
95
  isProcessing: false,
82
96
  };
97
+ let numCalls = 0;
83
98
  function triggerCallback(callback) {
84
99
  if (toKeepAlive.has(callback)) {
85
100
  step.schedule(callback);
86
101
  runNextFrame();
87
102
  }
103
+ numCalls++;
88
104
  callback(latestFrameData);
89
105
  }
90
106
  const step = {
@@ -125,6 +141,13 @@ function createRenderStep(runNextFrame) {
125
141
  [thisFrame, nextFrame] = [nextFrame, thisFrame];
126
142
  // Execute this frame
127
143
  thisFrame.forEach(triggerCallback);
144
+ /**
145
+ * If we're recording stats then
146
+ */
147
+ if (stepName && statsBuffer.value) {
148
+ statsBuffer.value.frameloop[stepName].push(numCalls);
149
+ }
150
+ numCalls = 0;
128
151
  // Clear the frame so no callbacks remain. This is to avoid
129
152
  // memory leaks should this render step not run for a while.
130
153
  thisFrame.clear();
@@ -138,14 +161,6 @@ function createRenderStep(runNextFrame) {
138
161
  return step;
139
162
  }
140
163
 
141
- const stepsOrder = [
142
- "read", // Read
143
- "resolveKeyframes", // Write/Read/Write/Read
144
- "update", // Compute
145
- "preRender", // Compute
146
- "render", // Write
147
- "postRender", // Compute
148
- ];
149
164
  const maxElapsed = 40;
150
165
  function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
151
166
  let runNextFrame = false;
@@ -157,7 +172,7 @@ function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
157
172
  };
158
173
  const flagRunNextFrame = () => (runNextFrame = true);
159
174
  const steps = stepsOrder.reduce((acc, key) => {
160
- acc[key] = createRenderStep(flagRunNextFrame);
175
+ acc[key] = createRenderStep(flagRunNextFrame, allowKeepAlive ? key : undefined);
161
176
  return acc;
162
177
  }, {});
163
178
  const { read, resolveKeyframes, update, preRender, render, postRender } = steps;
@@ -166,9 +181,11 @@ function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
166
181
  ? state.timestamp
167
182
  : performance.now();
168
183
  runNextFrame = false;
169
- state.delta = useDefaultElapsed
170
- ? 1000 / 60
171
- : Math.max(Math.min(timestamp - state.timestamp, maxElapsed), 1);
184
+ if (!MotionGlobalConfig.useManualTiming) {
185
+ state.delta = useDefaultElapsed
186
+ ? 1000 / 60
187
+ : Math.max(Math.min(timestamp - state.timestamp, maxElapsed), 1);
188
+ }
172
189
  state.timestamp = timestamp;
173
190
  state.isProcessing = true;
174
191
  // Unrolled render loop for better per-frame performance
@@ -393,7 +410,7 @@ class MotionValue {
393
410
  * This will be replaced by the build step with the latest version number.
394
411
  * When MotionValues are provided to motion components, warn if versions are mixed.
395
412
  */
396
- this.version = "12.3.1";
413
+ this.version = "12.4.1";
397
414
  /**
398
415
  * Tracks whether this value can output a velocity. Currently this is only true
399
416
  * if the value is numerical, but we might be able to widen the scope here and support
@@ -2986,7 +3003,7 @@ function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duratio
2986
3003
  */
2987
3004
  if (Array.isArray(easing))
2988
3005
  keyframeOptions.easing = easing;
2989
- return element.animate(keyframeOptions, {
3006
+ const animation = element.animate(keyframeOptions, {
2990
3007
  delay,
2991
3008
  duration,
2992
3009
  easing: !Array.isArray(easing) ? easing : "linear",
@@ -2994,6 +3011,7 @@ function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duratio
2994
3011
  iterations: repeat + 1,
2995
3012
  direction: repeatType === "reverse" ? "alternate" : "normal",
2996
3013
  });
3014
+ return animation;
2997
3015
  }
2998
3016
 
2999
3017
  const supportsWaapi = /*@__PURE__*/ motionUtils.memo(() => Object.hasOwnProperty.call(Element.prototype, "animate"));
@@ -3897,6 +3915,18 @@ function createAnimationState(visualElement) {
3897
3915
  */
3898
3916
  if (removedKeys.size) {
3899
3917
  const fallbackAnimation = {};
3918
+ /**
3919
+ * If the initial prop contains a transition we can use that, otherwise
3920
+ * allow the animation function to use the visual element's default.
3921
+ */
3922
+ if (typeof props.initial !== "boolean") {
3923
+ const initialTransition = resolveVariant(visualElement, Array.isArray(props.initial)
3924
+ ? props.initial[0]
3925
+ : props.initial);
3926
+ if (initialTransition && initialTransition.transition) {
3927
+ fallbackAnimation.transition = initialTransition.transition;
3928
+ }
3929
+ }
3900
3930
  removedKeys.forEach((key) => {
3901
3931
  const fallbackTarget = visualElement.getBaseTarget(key);
3902
3932
  const motionValue = visualElement.getValue(key);
@@ -4538,7 +4568,7 @@ function updateMotionValuesFromProps(element, next, prev) {
4538
4568
  * and warn against mismatches.
4539
4569
  */
4540
4570
  if (process.env.NODE_ENV === "development") {
4541
- warnOnce(nextValue.version === "12.3.1", `Attempting to mix Motion versions ${nextValue.version} with 12.3.1 may not work as expected.`);
4571
+ warnOnce(nextValue.version === "12.4.1", `Attempting to mix Motion versions ${nextValue.version} with 12.4.1 may not work as expected.`);
4542
4572
  }
4543
4573
  }
4544
4574
  else if (isMotionValue(prevValue)) {
@@ -6080,13 +6110,6 @@ const globalProjectionState = {
6080
6110
  hasEverUpdated: false,
6081
6111
  };
6082
6112
 
6083
- const metrics = {
6084
- type: "projectionFrame",
6085
- totalNodes: 0,
6086
- resolvedTargetDeltas: 0,
6087
- recalculatedProjection: 0,
6088
- };
6089
- const isDebug = typeof window !== "undefined" && window.MotionDebug !== undefined;
6090
6113
  const transformAxes = ["", "X", "Y", "Z"];
6091
6114
  const hiddenVisibility = { visibility: "hidden" };
6092
6115
  /**
@@ -6236,23 +6259,10 @@ function createProjectionNode$1({ attachResizeListener, defaultParent, measureSc
6236
6259
  */
6237
6260
  this.updateProjection = () => {
6238
6261
  this.projectionUpdateScheduled = false;
6239
- /**
6240
- * Reset debug counts. Manually resetting rather than creating a new
6241
- * object each frame.
6242
- */
6243
- if (isDebug) {
6244
- metrics.totalNodes =
6245
- metrics.resolvedTargetDeltas =
6246
- metrics.recalculatedProjection =
6247
- 0;
6248
- }
6249
6262
  this.nodes.forEach(propagateDirtyNodes);
6250
6263
  this.nodes.forEach(resolveTargetDelta);
6251
6264
  this.nodes.forEach(calcProjection);
6252
6265
  this.nodes.forEach(cleanDirtyNodes);
6253
- if (isDebug) {
6254
- window.MotionDebug.record(metrics);
6255
- }
6256
6266
  };
6257
6267
  /**
6258
6268
  * Frame calculations
@@ -6895,12 +6905,6 @@ function createProjectionNode$1({ attachResizeListener, defaultParent, measureSc
6895
6905
  this.relativeParent = this.relativeTarget = undefined;
6896
6906
  }
6897
6907
  }
6898
- /**
6899
- * Increase debug counter for resolved target deltas
6900
- */
6901
- if (isDebug) {
6902
- metrics.resolvedTargetDeltas++;
6903
- }
6904
6908
  }
6905
6909
  getClosestProjectingParent() {
6906
6910
  if (!this.parent ||
@@ -7026,12 +7030,6 @@ function createProjectionNode$1({ attachResizeListener, defaultParent, measureSc
7026
7030
  this.scheduleRender();
7027
7031
  this.notifyListeners("projectionUpdate", target);
7028
7032
  }
7029
- /**
7030
- * Increase debug counter for recalculated projections
7031
- */
7032
- if (isDebug) {
7033
- metrics.recalculatedProjection++;
7034
- }
7035
7033
  }
7036
7034
  hide() {
7037
7035
  this.isVisible = false;
@@ -7138,6 +7136,8 @@ function createProjectionNode$1({ attachResizeListener, defaultParent, measureSc
7138
7136
  this.mixTargetDelta(latest);
7139
7137
  options.onUpdate && options.onUpdate(latest);
7140
7138
  },
7139
+ onStop: () => {
7140
+ },
7141
7141
  onComplete: () => {
7142
7142
  options.onComplete && options.onComplete();
7143
7143
  this.completeAnimation();
@@ -7535,12 +7535,6 @@ function notifyLayoutUpdate(node) {
7535
7535
  node.options.transition = undefined;
7536
7536
  }
7537
7537
  function propagateDirtyNodes(node) {
7538
- /**
7539
- * Increase debug counter for nodes encountered this frame
7540
- */
7541
- if (isDebug) {
7542
- metrics.totalNodes++;
7543
- }
7544
7538
  if (!node.parent)
7545
7539
  return;
7546
7540
  /**
@@ -0,0 +1,288 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var motionUtils = require('motion-utils');
6
+
7
+ const stepsOrder = [
8
+ "read", // Read
9
+ "resolveKeyframes", // Write/Read/Write/Read
10
+ "update", // Compute
11
+ "preRender", // Compute
12
+ "render", // Write
13
+ "postRender", // Compute
14
+ ];
15
+
16
+ const statsBuffer = {
17
+ value: null,
18
+ addProjectionMetrics: null,
19
+ };
20
+
21
+ function createRenderStep(runNextFrame, stepName) {
22
+ /**
23
+ * We create and reuse two queues, one to queue jobs for the current frame
24
+ * and one for the next. We reuse to avoid triggering GC after x frames.
25
+ */
26
+ let thisFrame = new Set();
27
+ let nextFrame = new Set();
28
+ /**
29
+ * Track whether we're currently processing jobs in this step. This way
30
+ * we can decide whether to schedule new jobs for this frame or next.
31
+ */
32
+ let isProcessing = false;
33
+ let flushNextFrame = false;
34
+ /**
35
+ * A set of processes which were marked keepAlive when scheduled.
36
+ */
37
+ const toKeepAlive = new WeakSet();
38
+ let latestFrameData = {
39
+ delta: 0.0,
40
+ timestamp: 0.0,
41
+ isProcessing: false,
42
+ };
43
+ let numCalls = 0;
44
+ function triggerCallback(callback) {
45
+ if (toKeepAlive.has(callback)) {
46
+ step.schedule(callback);
47
+ runNextFrame();
48
+ }
49
+ numCalls++;
50
+ callback(latestFrameData);
51
+ }
52
+ const step = {
53
+ /**
54
+ * Schedule a process to run on the next frame.
55
+ */
56
+ schedule: (callback, keepAlive = false, immediate = false) => {
57
+ const addToCurrentFrame = immediate && isProcessing;
58
+ const queue = addToCurrentFrame ? thisFrame : nextFrame;
59
+ if (keepAlive)
60
+ toKeepAlive.add(callback);
61
+ if (!queue.has(callback))
62
+ queue.add(callback);
63
+ return callback;
64
+ },
65
+ /**
66
+ * Cancel the provided callback from running on the next frame.
67
+ */
68
+ cancel: (callback) => {
69
+ nextFrame.delete(callback);
70
+ toKeepAlive.delete(callback);
71
+ },
72
+ /**
73
+ * Execute all schedule callbacks.
74
+ */
75
+ process: (frameData) => {
76
+ latestFrameData = frameData;
77
+ /**
78
+ * If we're already processing we've probably been triggered by a flushSync
79
+ * inside an existing process. Instead of executing, mark flushNextFrame
80
+ * as true and ensure we flush the following frame at the end of this one.
81
+ */
82
+ if (isProcessing) {
83
+ flushNextFrame = true;
84
+ return;
85
+ }
86
+ isProcessing = true;
87
+ [thisFrame, nextFrame] = [nextFrame, thisFrame];
88
+ // Execute this frame
89
+ thisFrame.forEach(triggerCallback);
90
+ /**
91
+ * If we're recording stats then
92
+ */
93
+ if (stepName && statsBuffer.value) {
94
+ statsBuffer.value.frameloop[stepName].push(numCalls);
95
+ }
96
+ numCalls = 0;
97
+ // Clear the frame so no callbacks remain. This is to avoid
98
+ // memory leaks should this render step not run for a while.
99
+ thisFrame.clear();
100
+ isProcessing = false;
101
+ if (flushNextFrame) {
102
+ flushNextFrame = false;
103
+ step.process(frameData);
104
+ }
105
+ },
106
+ };
107
+ return step;
108
+ }
109
+
110
+ const maxElapsed = 40;
111
+ function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
112
+ let runNextFrame = false;
113
+ let useDefaultElapsed = true;
114
+ const state = {
115
+ delta: 0.0,
116
+ timestamp: 0.0,
117
+ isProcessing: false,
118
+ };
119
+ const flagRunNextFrame = () => (runNextFrame = true);
120
+ const steps = stepsOrder.reduce((acc, key) => {
121
+ acc[key] = createRenderStep(flagRunNextFrame, allowKeepAlive ? key : undefined);
122
+ return acc;
123
+ }, {});
124
+ const { read, resolveKeyframes, update, preRender, render, postRender } = steps;
125
+ const processBatch = () => {
126
+ const timestamp = performance.now();
127
+ runNextFrame = false;
128
+ {
129
+ state.delta = useDefaultElapsed
130
+ ? 1000 / 60
131
+ : Math.max(Math.min(timestamp - state.timestamp, maxElapsed), 1);
132
+ }
133
+ state.timestamp = timestamp;
134
+ state.isProcessing = true;
135
+ // Unrolled render loop for better per-frame performance
136
+ read.process(state);
137
+ resolveKeyframes.process(state);
138
+ update.process(state);
139
+ preRender.process(state);
140
+ render.process(state);
141
+ postRender.process(state);
142
+ state.isProcessing = false;
143
+ if (runNextFrame && allowKeepAlive) {
144
+ useDefaultElapsed = false;
145
+ scheduleNextBatch(processBatch);
146
+ }
147
+ };
148
+ const wake = () => {
149
+ runNextFrame = true;
150
+ useDefaultElapsed = true;
151
+ if (!state.isProcessing) {
152
+ scheduleNextBatch(processBatch);
153
+ }
154
+ };
155
+ const schedule = stepsOrder.reduce((acc, key) => {
156
+ const step = steps[key];
157
+ acc[key] = (process, keepAlive = false, immediate = false) => {
158
+ if (!runNextFrame)
159
+ wake();
160
+ return step.schedule(process, keepAlive, immediate);
161
+ };
162
+ return acc;
163
+ }, {});
164
+ const cancel = (process) => {
165
+ for (let i = 0; i < stepsOrder.length; i++) {
166
+ steps[stepsOrder[i]].cancel(process);
167
+ }
168
+ };
169
+ return { schedule, cancel, state, steps };
170
+ }
171
+
172
+ const { schedule: frame, cancel: cancelFrame, state: frameData, steps: frameSteps, } = createRenderBatcher(typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : motionUtils.noop, true);
173
+
174
+ const activeAnimations = {
175
+ layout: 0,
176
+ mainThread: 0,
177
+ waapi: 0,
178
+ };
179
+
180
+ function record() {
181
+ const { value } = statsBuffer;
182
+ if (value === null) {
183
+ cancelFrame(record);
184
+ return;
185
+ }
186
+ value.frameloop.rate.push(frameData.delta);
187
+ value.animations.mainThread.push(activeAnimations.mainThread);
188
+ value.animations.waapi.push(activeAnimations.waapi);
189
+ value.animations.layout.push(activeAnimations.layout);
190
+ }
191
+ function mean(values) {
192
+ return values.reduce((acc, value) => acc + value, 0) / values.length;
193
+ }
194
+ function summarise(values, calcAverage = mean) {
195
+ if (values.length === 0) {
196
+ return {
197
+ min: 0,
198
+ max: 0,
199
+ avg: 0,
200
+ };
201
+ }
202
+ return {
203
+ min: Math.min(...values),
204
+ max: Math.max(...values),
205
+ avg: calcAverage(values),
206
+ };
207
+ }
208
+ const msToFps = (ms) => Math.round(1000 / ms);
209
+ function clearStatsBuffer() {
210
+ statsBuffer.value = null;
211
+ statsBuffer.addProjectionMetrics = null;
212
+ }
213
+ function reportStats() {
214
+ const { value } = statsBuffer;
215
+ if (!value) {
216
+ throw new Error("Stats are not being measured");
217
+ }
218
+ clearStatsBuffer();
219
+ cancelFrame(record);
220
+ const summary = {
221
+ frameloop: {
222
+ rate: summarise(value.frameloop.rate),
223
+ read: summarise(value.frameloop.read),
224
+ resolveKeyframes: summarise(value.frameloop.resolveKeyframes),
225
+ update: summarise(value.frameloop.update),
226
+ preRender: summarise(value.frameloop.preRender),
227
+ render: summarise(value.frameloop.render),
228
+ postRender: summarise(value.frameloop.postRender),
229
+ },
230
+ animations: {
231
+ mainThread: summarise(value.animations.mainThread),
232
+ waapi: summarise(value.animations.waapi),
233
+ layout: summarise(value.animations.layout),
234
+ },
235
+ layoutProjection: {
236
+ nodes: summarise(value.layoutProjection.nodes),
237
+ calculatedTargetDeltas: summarise(value.layoutProjection.calculatedTargetDeltas),
238
+ calculatedProjections: summarise(value.layoutProjection.calculatedProjections),
239
+ },
240
+ };
241
+ /**
242
+ * Convert the rate to FPS
243
+ */
244
+ const { rate } = summary.frameloop;
245
+ rate.min = msToFps(rate.min);
246
+ rate.max = msToFps(rate.max);
247
+ rate.avg = msToFps(rate.avg);
248
+ [rate.min, rate.max] = [rate.max, rate.min];
249
+ return summary;
250
+ }
251
+ function recordStats() {
252
+ if (statsBuffer.value) {
253
+ clearStatsBuffer();
254
+ throw new Error("Stats are already being measured");
255
+ }
256
+ const newStatsBuffer = statsBuffer;
257
+ newStatsBuffer.value = {
258
+ frameloop: {
259
+ rate: [],
260
+ read: [],
261
+ resolveKeyframes: [],
262
+ update: [],
263
+ preRender: [],
264
+ render: [],
265
+ postRender: [],
266
+ },
267
+ animations: {
268
+ mainThread: [],
269
+ waapi: [],
270
+ layout: [],
271
+ },
272
+ layoutProjection: {
273
+ nodes: [],
274
+ calculatedTargetDeltas: [],
275
+ calculatedProjections: [],
276
+ },
277
+ };
278
+ newStatsBuffer.addProjectionMetrics = (metrics) => {
279
+ const { layoutProjection } = newStatsBuffer.value;
280
+ layoutProjection.nodes.push(metrics.nodes);
281
+ layoutProjection.calculatedTargetDeltas.push(metrics.calculatedTargetDeltas);
282
+ layoutProjection.calculatedProjections.push(metrics.calculatedProjections);
283
+ };
284
+ frame.postRender(record, true);
285
+ return reportStats;
286
+ }
287
+
288
+ exports.recordStats = recordStats;
@@ -408,7 +408,7 @@ function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duratio
408
408
  */
409
409
  if (Array.isArray(easing))
410
410
  keyframeOptions.easing = easing;
411
- return element.animate(keyframeOptions, {
411
+ const animation = element.animate(keyframeOptions, {
412
412
  delay,
413
413
  duration,
414
414
  easing: !Array.isArray(easing) ? easing : "linear",
@@ -416,6 +416,7 @@ function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duratio
416
416
  iterations: repeat + 1,
417
417
  direction: repeatType === "reverse" ? "alternate" : "normal",
418
418
  });
419
+ return animation;
419
420
  }
420
421
 
421
422
  const createUnitType = (unit) => ({
package/dist/cjs/dom.js CHANGED
@@ -697,7 +697,21 @@ const MotionGlobalConfig = {
697
697
  useManualTiming: false,
698
698
  };
699
699
 
700
- function createRenderStep(runNextFrame) {
700
+ const stepsOrder = [
701
+ "read", // Read
702
+ "resolveKeyframes", // Write/Read/Write/Read
703
+ "update", // Compute
704
+ "preRender", // Compute
705
+ "render", // Write
706
+ "postRender", // Compute
707
+ ];
708
+
709
+ const statsBuffer = {
710
+ value: null,
711
+ addProjectionMetrics: null,
712
+ };
713
+
714
+ function createRenderStep(runNextFrame, stepName) {
701
715
  /**
702
716
  * We create and reuse two queues, one to queue jobs for the current frame
703
717
  * and one for the next. We reuse to avoid triggering GC after x frames.
@@ -719,11 +733,13 @@ function createRenderStep(runNextFrame) {
719
733
  timestamp: 0.0,
720
734
  isProcessing: false,
721
735
  };
736
+ let numCalls = 0;
722
737
  function triggerCallback(callback) {
723
738
  if (toKeepAlive.has(callback)) {
724
739
  step.schedule(callback);
725
740
  runNextFrame();
726
741
  }
742
+ numCalls++;
727
743
  callback(latestFrameData);
728
744
  }
729
745
  const step = {
@@ -764,6 +780,13 @@ function createRenderStep(runNextFrame) {
764
780
  [thisFrame, nextFrame] = [nextFrame, thisFrame];
765
781
  // Execute this frame
766
782
  thisFrame.forEach(triggerCallback);
783
+ /**
784
+ * If we're recording stats then
785
+ */
786
+ if (stepName && statsBuffer.value) {
787
+ statsBuffer.value.frameloop[stepName].push(numCalls);
788
+ }
789
+ numCalls = 0;
767
790
  // Clear the frame so no callbacks remain. This is to avoid
768
791
  // memory leaks should this render step not run for a while.
769
792
  thisFrame.clear();
@@ -777,14 +800,6 @@ function createRenderStep(runNextFrame) {
777
800
  return step;
778
801
  }
779
802
 
780
- const stepsOrder = [
781
- "read", // Read
782
- "resolveKeyframes", // Write/Read/Write/Read
783
- "update", // Compute
784
- "preRender", // Compute
785
- "render", // Write
786
- "postRender", // Compute
787
- ];
788
803
  const maxElapsed$1 = 40;
789
804
  function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
790
805
  let runNextFrame = false;
@@ -796,16 +811,18 @@ function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
796
811
  };
797
812
  const flagRunNextFrame = () => (runNextFrame = true);
798
813
  const steps = stepsOrder.reduce((acc, key) => {
799
- acc[key] = createRenderStep(flagRunNextFrame);
814
+ acc[key] = createRenderStep(flagRunNextFrame, allowKeepAlive ? key : undefined);
800
815
  return acc;
801
816
  }, {});
802
817
  const { read, resolveKeyframes, update, preRender, render, postRender } = steps;
803
818
  const processBatch = () => {
804
819
  const timestamp = performance.now();
805
820
  runNextFrame = false;
806
- state.delta = useDefaultElapsed
807
- ? 1000 / 60
808
- : Math.max(Math.min(timestamp - state.timestamp, maxElapsed$1), 1);
821
+ {
822
+ state.delta = useDefaultElapsed
823
+ ? 1000 / 60
824
+ : Math.max(Math.min(timestamp - state.timestamp, maxElapsed$1), 1);
825
+ }
809
826
  state.timestamp = timestamp;
810
827
  state.isProcessing = true;
811
828
  // Unrolled render loop for better per-frame performance
@@ -994,7 +1011,7 @@ class MotionValue {
994
1011
  * This will be replaced by the build step with the latest version number.
995
1012
  * When MotionValues are provided to motion components, warn if versions are mixed.
996
1013
  */
997
- this.version = "12.3.1";
1014
+ this.version = "12.4.1";
998
1015
  /**
999
1016
  * Tracks whether this value can output a velocity. Currently this is only true
1000
1017
  * if the value is numerical, but we might be able to widen the scope here and support
@@ -3293,7 +3310,7 @@ function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duratio
3293
3310
  */
3294
3311
  if (Array.isArray(easing))
3295
3312
  keyframeOptions.easing = easing;
3296
- return element.animate(keyframeOptions, {
3313
+ const animation = element.animate(keyframeOptions, {
3297
3314
  delay,
3298
3315
  duration,
3299
3316
  easing: !Array.isArray(easing) ? easing : "linear",
@@ -3301,6 +3318,7 @@ function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duratio
3301
3318
  iterations: repeat + 1,
3302
3319
  direction: repeatType === "reverse" ? "alternate" : "normal",
3303
3320
  });
3321
+ return animation;
3304
3322
  }
3305
3323
 
3306
3324
  const supportsWaapi = /*@__PURE__*/ motionUtils.memo(() => Object.hasOwnProperty.call(Element.prototype, "animate"));
@@ -3928,7 +3946,7 @@ function updateMotionValuesFromProps(element, next, prev) {
3928
3946
  * and warn against mismatches.
3929
3947
  */
3930
3948
  if (process.env.NODE_ENV === "development") {
3931
- warnOnce(nextValue.version === "12.3.1", `Attempting to mix Motion versions ${nextValue.version} with 12.3.1 may not work as expected.`);
3949
+ warnOnce(nextValue.version === "12.4.1", `Attempting to mix Motion versions ${nextValue.version} with 12.4.1 may not work as expected.`);
3932
3950
  }
3933
3951
  }
3934
3952
  else if (isMotionValue(prevValue)) {