framer-motion 11.0.0-alpha.1 → 11.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/dom-entry.js +1 -1
- package/dist/cjs/{index-legacy-4be91252.js → index-legacy-731c5510.js} +173 -172
- package/dist/cjs/index.js +17 -16
- package/dist/es/frameloop/batcher.mjs +3 -1
- package/dist/es/frameloop/sync-time.mjs +1 -2
- package/dist/es/motion/features/layout/MeasureLayout.mjs +2 -1
- package/dist/es/motion/utils/use-visual-element.mjs +2 -1
- package/dist/es/projection/node/create-projection-node.mjs +2 -3
- package/dist/es/render/utils/motion-values.mjs +1 -1
- package/dist/es/value/index.mjs +1 -1
- package/dist/es/value/use-spring.mjs +7 -11
- package/dist/es/value/use-velocity.mjs +4 -0
- package/dist/framer-motion.dev.js +188 -187
- package/dist/framer-motion.js +1 -1
- package/dist/projection.dev.js +9 -9
- package/package.json +8 -8
|
@@ -57,6 +57,177 @@
|
|
|
57
57
|
const optimizedAppearDataId = "framerAppearId";
|
|
58
58
|
const optimizedAppearDataAttribute = "data-" + camelToDash(optimizedAppearDataId);
|
|
59
59
|
|
|
60
|
+
const MotionGlobalConfig = {
|
|
61
|
+
skipAnimations: false,
|
|
62
|
+
useManualTiming: false,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
class Queue {
|
|
66
|
+
constructor() {
|
|
67
|
+
this.order = [];
|
|
68
|
+
this.scheduled = new Set();
|
|
69
|
+
}
|
|
70
|
+
add(process) {
|
|
71
|
+
if (!this.scheduled.has(process)) {
|
|
72
|
+
this.scheduled.add(process);
|
|
73
|
+
this.order.push(process);
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
remove(process) {
|
|
78
|
+
const index = this.order.indexOf(process);
|
|
79
|
+
if (index !== -1) {
|
|
80
|
+
this.order.splice(index, 1);
|
|
81
|
+
this.scheduled.delete(process);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
clear() {
|
|
85
|
+
this.order.length = 0;
|
|
86
|
+
this.scheduled.clear();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function createRenderStep(runNextFrame) {
|
|
90
|
+
/**
|
|
91
|
+
* We create and reuse two queues, one to queue jobs for the current frame
|
|
92
|
+
* and one for the next. We reuse to avoid triggering GC after x frames.
|
|
93
|
+
*/
|
|
94
|
+
let thisFrame = new Queue();
|
|
95
|
+
let nextFrame = new Queue();
|
|
96
|
+
let numToRun = 0;
|
|
97
|
+
/**
|
|
98
|
+
* Track whether we're currently processing jobs in this step. This way
|
|
99
|
+
* we can decide whether to schedule new jobs for this frame or next.
|
|
100
|
+
*/
|
|
101
|
+
let isProcessing = false;
|
|
102
|
+
let flushNextFrame = false;
|
|
103
|
+
/**
|
|
104
|
+
* A set of processes which were marked keepAlive when scheduled.
|
|
105
|
+
*/
|
|
106
|
+
const toKeepAlive = new WeakSet();
|
|
107
|
+
const step = {
|
|
108
|
+
/**
|
|
109
|
+
* Schedule a process to run on the next frame.
|
|
110
|
+
*/
|
|
111
|
+
schedule: (callback, keepAlive = false, immediate = false) => {
|
|
112
|
+
const addToCurrentFrame = immediate && isProcessing;
|
|
113
|
+
const queue = addToCurrentFrame ? thisFrame : nextFrame;
|
|
114
|
+
if (keepAlive)
|
|
115
|
+
toKeepAlive.add(callback);
|
|
116
|
+
if (queue.add(callback) && addToCurrentFrame && isProcessing) {
|
|
117
|
+
// If we're adding it to the currently running queue, update its measured size
|
|
118
|
+
numToRun = thisFrame.order.length;
|
|
119
|
+
}
|
|
120
|
+
return callback;
|
|
121
|
+
},
|
|
122
|
+
/**
|
|
123
|
+
* Cancel the provided callback from running on the next frame.
|
|
124
|
+
*/
|
|
125
|
+
cancel: (callback) => {
|
|
126
|
+
nextFrame.remove(callback);
|
|
127
|
+
toKeepAlive.delete(callback);
|
|
128
|
+
},
|
|
129
|
+
/**
|
|
130
|
+
* Execute all schedule callbacks.
|
|
131
|
+
*/
|
|
132
|
+
process: (frameData) => {
|
|
133
|
+
/**
|
|
134
|
+
* If we're already processing we've probably been triggered by a flushSync
|
|
135
|
+
* inside an existing process. Instead of executing, mark flushNextFrame
|
|
136
|
+
* as true and ensure we flush the following frame at the end of this one.
|
|
137
|
+
*/
|
|
138
|
+
if (isProcessing) {
|
|
139
|
+
flushNextFrame = true;
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
isProcessing = true;
|
|
143
|
+
[thisFrame, nextFrame] = [nextFrame, thisFrame];
|
|
144
|
+
// Clear the next frame queue
|
|
145
|
+
nextFrame.clear();
|
|
146
|
+
// Execute this frame
|
|
147
|
+
numToRun = thisFrame.order.length;
|
|
148
|
+
if (numToRun) {
|
|
149
|
+
for (let i = 0; i < numToRun; i++) {
|
|
150
|
+
const callback = thisFrame.order[i];
|
|
151
|
+
if (toKeepAlive.has(callback)) {
|
|
152
|
+
step.schedule(callback);
|
|
153
|
+
runNextFrame();
|
|
154
|
+
}
|
|
155
|
+
callback(frameData);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
isProcessing = false;
|
|
159
|
+
if (flushNextFrame) {
|
|
160
|
+
flushNextFrame = false;
|
|
161
|
+
step.process(frameData);
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
return step;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const stepsOrder = [
|
|
169
|
+
"prepare",
|
|
170
|
+
"read",
|
|
171
|
+
"update",
|
|
172
|
+
"preRender",
|
|
173
|
+
"render",
|
|
174
|
+
"postRender",
|
|
175
|
+
];
|
|
176
|
+
const maxElapsed$1 = 40;
|
|
177
|
+
function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
178
|
+
let runNextFrame = false;
|
|
179
|
+
let useDefaultElapsed = true;
|
|
180
|
+
const state = {
|
|
181
|
+
delta: 0,
|
|
182
|
+
timestamp: 0,
|
|
183
|
+
isProcessing: false,
|
|
184
|
+
};
|
|
185
|
+
const steps = stepsOrder.reduce((acc, key) => {
|
|
186
|
+
acc[key] = createRenderStep(() => (runNextFrame = true));
|
|
187
|
+
return acc;
|
|
188
|
+
}, {});
|
|
189
|
+
const processStep = (stepId) => {
|
|
190
|
+
steps[stepId].process(state);
|
|
191
|
+
};
|
|
192
|
+
const processBatch = () => {
|
|
193
|
+
const timestamp = MotionGlobalConfig.useManualTiming
|
|
194
|
+
? state.timestamp
|
|
195
|
+
: performance.now();
|
|
196
|
+
runNextFrame = false;
|
|
197
|
+
state.delta = useDefaultElapsed
|
|
198
|
+
? 1000 / 60
|
|
199
|
+
: Math.max(Math.min(timestamp - state.timestamp, maxElapsed$1), 1);
|
|
200
|
+
state.timestamp = timestamp;
|
|
201
|
+
state.isProcessing = true;
|
|
202
|
+
stepsOrder.forEach(processStep);
|
|
203
|
+
state.isProcessing = false;
|
|
204
|
+
if (runNextFrame && allowKeepAlive) {
|
|
205
|
+
useDefaultElapsed = false;
|
|
206
|
+
scheduleNextBatch(processBatch);
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
const wake = () => {
|
|
210
|
+
runNextFrame = true;
|
|
211
|
+
useDefaultElapsed = true;
|
|
212
|
+
if (!state.isProcessing) {
|
|
213
|
+
scheduleNextBatch(processBatch);
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
const schedule = stepsOrder.reduce((acc, key) => {
|
|
217
|
+
const step = steps[key];
|
|
218
|
+
acc[key] = (process, keepAlive = false, immediate = false) => {
|
|
219
|
+
if (!runNextFrame)
|
|
220
|
+
wake();
|
|
221
|
+
return step.schedule(process, keepAlive, immediate);
|
|
222
|
+
};
|
|
223
|
+
return acc;
|
|
224
|
+
}, {});
|
|
225
|
+
const cancel = (process) => stepsOrder.forEach((key) => steps[key].cancel(process));
|
|
226
|
+
return { schedule, cancel, state, steps };
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const { schedule: microtask, cancel: cancelMicrotask } = createRenderBatcher(queueMicrotask, false);
|
|
230
|
+
|
|
60
231
|
function useVisualElement(Component, visualState, props, createVisualElement) {
|
|
61
232
|
const { visualElement: parent } = React.useContext(MotionContext);
|
|
62
233
|
const lazyContext = React.useContext(LazyContext);
|
|
@@ -91,7 +262,7 @@
|
|
|
91
262
|
useIsomorphicLayoutEffect(() => {
|
|
92
263
|
if (!visualElement)
|
|
93
264
|
return;
|
|
94
|
-
visualElement.render
|
|
265
|
+
microtask.postRender(visualElement.render);
|
|
95
266
|
/**
|
|
96
267
|
* Ideally this function would always run in a useEffect.
|
|
97
268
|
*
|
|
@@ -1221,173 +1392,6 @@
|
|
|
1221
1392
|
|
|
1222
1393
|
const noop = (any) => any;
|
|
1223
1394
|
|
|
1224
|
-
const MotionGlobalConfig = {
|
|
1225
|
-
skipAnimations: false,
|
|
1226
|
-
useManualTiming: false,
|
|
1227
|
-
};
|
|
1228
|
-
|
|
1229
|
-
class Queue {
|
|
1230
|
-
constructor() {
|
|
1231
|
-
this.order = [];
|
|
1232
|
-
this.scheduled = new Set();
|
|
1233
|
-
}
|
|
1234
|
-
add(process) {
|
|
1235
|
-
if (!this.scheduled.has(process)) {
|
|
1236
|
-
this.scheduled.add(process);
|
|
1237
|
-
this.order.push(process);
|
|
1238
|
-
return true;
|
|
1239
|
-
}
|
|
1240
|
-
}
|
|
1241
|
-
remove(process) {
|
|
1242
|
-
const index = this.order.indexOf(process);
|
|
1243
|
-
if (index !== -1) {
|
|
1244
|
-
this.order.splice(index, 1);
|
|
1245
|
-
this.scheduled.delete(process);
|
|
1246
|
-
}
|
|
1247
|
-
}
|
|
1248
|
-
clear() {
|
|
1249
|
-
this.order.length = 0;
|
|
1250
|
-
this.scheduled.clear();
|
|
1251
|
-
}
|
|
1252
|
-
}
|
|
1253
|
-
function createRenderStep(runNextFrame) {
|
|
1254
|
-
/**
|
|
1255
|
-
* We create and reuse two queues, one to queue jobs for the current frame
|
|
1256
|
-
* and one for the next. We reuse to avoid triggering GC after x frames.
|
|
1257
|
-
*/
|
|
1258
|
-
let thisFrame = new Queue();
|
|
1259
|
-
let nextFrame = new Queue();
|
|
1260
|
-
let numToRun = 0;
|
|
1261
|
-
/**
|
|
1262
|
-
* Track whether we're currently processing jobs in this step. This way
|
|
1263
|
-
* we can decide whether to schedule new jobs for this frame or next.
|
|
1264
|
-
*/
|
|
1265
|
-
let isProcessing = false;
|
|
1266
|
-
let flushNextFrame = false;
|
|
1267
|
-
/**
|
|
1268
|
-
* A set of processes which were marked keepAlive when scheduled.
|
|
1269
|
-
*/
|
|
1270
|
-
const toKeepAlive = new WeakSet();
|
|
1271
|
-
const step = {
|
|
1272
|
-
/**
|
|
1273
|
-
* Schedule a process to run on the next frame.
|
|
1274
|
-
*/
|
|
1275
|
-
schedule: (callback, keepAlive = false, immediate = false) => {
|
|
1276
|
-
const addToCurrentFrame = immediate && isProcessing;
|
|
1277
|
-
const queue = addToCurrentFrame ? thisFrame : nextFrame;
|
|
1278
|
-
if (keepAlive)
|
|
1279
|
-
toKeepAlive.add(callback);
|
|
1280
|
-
if (queue.add(callback) && addToCurrentFrame && isProcessing) {
|
|
1281
|
-
// If we're adding it to the currently running queue, update its measured size
|
|
1282
|
-
numToRun = thisFrame.order.length;
|
|
1283
|
-
}
|
|
1284
|
-
return callback;
|
|
1285
|
-
},
|
|
1286
|
-
/**
|
|
1287
|
-
* Cancel the provided callback from running on the next frame.
|
|
1288
|
-
*/
|
|
1289
|
-
cancel: (callback) => {
|
|
1290
|
-
nextFrame.remove(callback);
|
|
1291
|
-
toKeepAlive.delete(callback);
|
|
1292
|
-
},
|
|
1293
|
-
/**
|
|
1294
|
-
* Execute all schedule callbacks.
|
|
1295
|
-
*/
|
|
1296
|
-
process: (frameData) => {
|
|
1297
|
-
/**
|
|
1298
|
-
* If we're already processing we've probably been triggered by a flushSync
|
|
1299
|
-
* inside an existing process. Instead of executing, mark flushNextFrame
|
|
1300
|
-
* as true and ensure we flush the following frame at the end of this one.
|
|
1301
|
-
*/
|
|
1302
|
-
if (isProcessing) {
|
|
1303
|
-
flushNextFrame = true;
|
|
1304
|
-
return;
|
|
1305
|
-
}
|
|
1306
|
-
isProcessing = true;
|
|
1307
|
-
[thisFrame, nextFrame] = [nextFrame, thisFrame];
|
|
1308
|
-
// Clear the next frame queue
|
|
1309
|
-
nextFrame.clear();
|
|
1310
|
-
// Execute this frame
|
|
1311
|
-
numToRun = thisFrame.order.length;
|
|
1312
|
-
if (numToRun) {
|
|
1313
|
-
for (let i = 0; i < numToRun; i++) {
|
|
1314
|
-
const callback = thisFrame.order[i];
|
|
1315
|
-
if (toKeepAlive.has(callback)) {
|
|
1316
|
-
step.schedule(callback);
|
|
1317
|
-
runNextFrame();
|
|
1318
|
-
}
|
|
1319
|
-
callback(frameData);
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
isProcessing = false;
|
|
1323
|
-
if (flushNextFrame) {
|
|
1324
|
-
flushNextFrame = false;
|
|
1325
|
-
step.process(frameData);
|
|
1326
|
-
}
|
|
1327
|
-
},
|
|
1328
|
-
};
|
|
1329
|
-
return step;
|
|
1330
|
-
}
|
|
1331
|
-
|
|
1332
|
-
const stepsOrder = [
|
|
1333
|
-
"prepare",
|
|
1334
|
-
"read",
|
|
1335
|
-
"update",
|
|
1336
|
-
"preRender",
|
|
1337
|
-
"render",
|
|
1338
|
-
"postRender",
|
|
1339
|
-
];
|
|
1340
|
-
const maxElapsed$1 = 40;
|
|
1341
|
-
function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
1342
|
-
let runNextFrame = false;
|
|
1343
|
-
let useDefaultElapsed = true;
|
|
1344
|
-
const state = {
|
|
1345
|
-
delta: 0,
|
|
1346
|
-
timestamp: 0,
|
|
1347
|
-
isProcessing: false,
|
|
1348
|
-
};
|
|
1349
|
-
const steps = stepsOrder.reduce((acc, key) => {
|
|
1350
|
-
acc[key] = createRenderStep(() => (runNextFrame = true));
|
|
1351
|
-
return acc;
|
|
1352
|
-
}, {});
|
|
1353
|
-
const processStep = (stepId) => steps[stepId].process(state);
|
|
1354
|
-
const processBatch = () => {
|
|
1355
|
-
const timestamp = MotionGlobalConfig.useManualTiming
|
|
1356
|
-
? state.timestamp
|
|
1357
|
-
: performance.now();
|
|
1358
|
-
runNextFrame = false;
|
|
1359
|
-
state.delta = useDefaultElapsed
|
|
1360
|
-
? 1000 / 60
|
|
1361
|
-
: Math.max(Math.min(timestamp - state.timestamp, maxElapsed$1), 1);
|
|
1362
|
-
state.timestamp = timestamp;
|
|
1363
|
-
state.isProcessing = true;
|
|
1364
|
-
stepsOrder.forEach(processStep);
|
|
1365
|
-
state.isProcessing = false;
|
|
1366
|
-
if (runNextFrame && allowKeepAlive) {
|
|
1367
|
-
useDefaultElapsed = false;
|
|
1368
|
-
scheduleNextBatch(processBatch);
|
|
1369
|
-
}
|
|
1370
|
-
};
|
|
1371
|
-
const wake = () => {
|
|
1372
|
-
runNextFrame = true;
|
|
1373
|
-
useDefaultElapsed = true;
|
|
1374
|
-
if (!state.isProcessing) {
|
|
1375
|
-
scheduleNextBatch(processBatch);
|
|
1376
|
-
}
|
|
1377
|
-
};
|
|
1378
|
-
const schedule = stepsOrder.reduce((acc, key) => {
|
|
1379
|
-
const step = steps[key];
|
|
1380
|
-
acc[key] = (process, keepAlive = false, immediate = false) => {
|
|
1381
|
-
if (!runNextFrame)
|
|
1382
|
-
wake();
|
|
1383
|
-
return step.schedule(process, keepAlive, immediate);
|
|
1384
|
-
};
|
|
1385
|
-
return acc;
|
|
1386
|
-
}, {});
|
|
1387
|
-
const cancel = (process) => stepsOrder.forEach((key) => steps[key].cancel(process));
|
|
1388
|
-
return { schedule, cancel, state, steps };
|
|
1389
|
-
}
|
|
1390
|
-
|
|
1391
1395
|
const { schedule: frame, cancel: cancelFrame, state: frameData, steps, } = createRenderBatcher(typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : noop, true);
|
|
1392
1396
|
|
|
1393
1397
|
const svgMotionConfig = {
|
|
@@ -2909,8 +2913,6 @@
|
|
|
2909
2913
|
};
|
|
2910
2914
|
}
|
|
2911
2915
|
|
|
2912
|
-
const { schedule: microtask, cancel: cancelMicrotask } = createRenderBatcher(queueMicrotask, false);
|
|
2913
|
-
|
|
2914
2916
|
let now;
|
|
2915
2917
|
function clearTime() {
|
|
2916
2918
|
now = undefined;
|
|
@@ -2934,7 +2936,7 @@
|
|
|
2934
2936
|
},
|
|
2935
2937
|
set: (newTime) => {
|
|
2936
2938
|
now = newTime;
|
|
2937
|
-
|
|
2939
|
+
queueMicrotask(clearTime);
|
|
2938
2940
|
},
|
|
2939
2941
|
};
|
|
2940
2942
|
|
|
@@ -3895,7 +3897,7 @@
|
|
|
3895
3897
|
* This will be replaced by the build step with the latest version number.
|
|
3896
3898
|
* When MotionValues are provided to motion components, warn if versions are mixed.
|
|
3897
3899
|
*/
|
|
3898
|
-
this.version = "11.0.0
|
|
3900
|
+
this.version = "11.0.0";
|
|
3899
3901
|
/**
|
|
3900
3902
|
* Tracks whether this value can output a velocity. Currently this is only true
|
|
3901
3903
|
* if the value is numerical, but we might be able to widen the scope here and support
|
|
@@ -6783,7 +6785,7 @@
|
|
|
6783
6785
|
* and warn against mismatches.
|
|
6784
6786
|
*/
|
|
6785
6787
|
{
|
|
6786
|
-
warnOnce(nextValue.version === "11.0.0
|
|
6788
|
+
warnOnce(nextValue.version === "11.0.0", `Attempting to mix Framer Motion versions ${nextValue.version} with 11.0.0 may not work as expected.`);
|
|
6787
6789
|
}
|
|
6788
6790
|
}
|
|
6789
6791
|
else if (isMotionValue(prevValue)) {
|
|
@@ -8800,7 +8802,7 @@
|
|
|
8800
8802
|
didUpdate() {
|
|
8801
8803
|
if (!this.updateScheduled) {
|
|
8802
8804
|
this.updateScheduled = true;
|
|
8803
|
-
|
|
8805
|
+
microtask.read(() => this.update());
|
|
8804
8806
|
}
|
|
8805
8807
|
}
|
|
8806
8808
|
clearAllSnapshots() {
|
|
@@ -9082,9 +9084,7 @@
|
|
|
9082
9084
|
* a relativeParent. This will allow a component to perform scale correction
|
|
9083
9085
|
* even if no animation has started.
|
|
9084
9086
|
*/
|
|
9085
|
-
// TODO If this is unsuccessful this currently happens every frame
|
|
9086
9087
|
if (!this.targetDelta && !this.relativeTarget) {
|
|
9087
|
-
// TODO: This is a semi-repetition of further down this function, make DRY
|
|
9088
9088
|
const relativeParent = this.getClosestProjectingParent();
|
|
9089
9089
|
if (relativeParent &&
|
|
9090
9090
|
relativeParent.layout &&
|
|
@@ -10148,7 +10148,7 @@
|
|
|
10148
10148
|
const { projection } = this.props.visualElement;
|
|
10149
10149
|
if (projection) {
|
|
10150
10150
|
projection.root.didUpdate();
|
|
10151
|
-
|
|
10151
|
+
microtask.postRender(() => {
|
|
10152
10152
|
if (!projection.currentAnimation && projection.isLead()) {
|
|
10153
10153
|
this.safeToRemove();
|
|
10154
10154
|
}
|
|
@@ -10976,6 +10976,13 @@
|
|
|
10976
10976
|
*/
|
|
10977
10977
|
if (isStatic)
|
|
10978
10978
|
return set(v);
|
|
10979
|
+
/**
|
|
10980
|
+
* If the previous animation hasn't had the chance to even render a frame, render it now.
|
|
10981
|
+
*/
|
|
10982
|
+
const animation = activeSpringAnimation.current;
|
|
10983
|
+
if (animation && animation.time === 0) {
|
|
10984
|
+
animation.sample(frameData.delta);
|
|
10985
|
+
}
|
|
10979
10986
|
stopAnimation();
|
|
10980
10987
|
activeSpringAnimation.current = animateValue({
|
|
10981
10988
|
keyframes: [value.get(), v],
|
|
@@ -10986,16 +10993,6 @@
|
|
|
10986
10993
|
...config,
|
|
10987
10994
|
onUpdate: set,
|
|
10988
10995
|
});
|
|
10989
|
-
/**
|
|
10990
|
-
* If we're between frames, resync the animation to the frameloop.
|
|
10991
|
-
*/
|
|
10992
|
-
if (!frameData.isProcessing) {
|
|
10993
|
-
const delta = performance.now() - frameData.timestamp;
|
|
10994
|
-
if (delta < 30) {
|
|
10995
|
-
activeSpringAnimation.current.time =
|
|
10996
|
-
millisecondsToSeconds(delta);
|
|
10997
|
-
}
|
|
10998
|
-
}
|
|
10999
10996
|
return value.get();
|
|
11000
10997
|
}, stopAnimation);
|
|
11001
10998
|
}, [JSON.stringify(config)]);
|
|
@@ -11033,6 +11030,10 @@
|
|
|
11033
11030
|
const updateVelocity = () => {
|
|
11034
11031
|
const latest = value.getVelocity();
|
|
11035
11032
|
velocity.set(latest);
|
|
11033
|
+
/**
|
|
11034
|
+
* If we still have velocity, schedule an update for the next frame
|
|
11035
|
+
* to keep checking until it is zero.
|
|
11036
|
+
*/
|
|
11036
11037
|
if (latest)
|
|
11037
11038
|
frame.update(updateVelocity);
|
|
11038
11039
|
};
|