framer-motion 12.7.3 → 12.7.5-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 (155) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/client.js +1 -1
  3. package/dist/cjs/{create-DwAwaNot.js → create-C7kXmWbI.js} +99 -2828
  4. package/dist/cjs/dom-mini.js +82 -66
  5. package/dist/cjs/dom.js +264 -3000
  6. package/dist/cjs/index.js +163 -218
  7. package/dist/cjs/m.js +13 -170
  8. package/dist/cjs/mini.js +77 -9
  9. package/dist/dom-mini.js +1 -1
  10. package/dist/dom.d.ts +5 -94
  11. package/dist/dom.js +1 -1
  12. package/dist/es/animation/animate/sequence.mjs +1 -1
  13. package/dist/es/animation/animators/waapi/animate-elements.mjs +78 -10
  14. package/dist/es/animation/interfaces/motion-value.mjs +11 -30
  15. package/dist/es/animation/interfaces/visual-element-target.mjs +1 -2
  16. package/dist/es/animation/optimized-appear/store-id.mjs +1 -1
  17. package/dist/es/animation/sequence/create.mjs +2 -5
  18. package/dist/es/animation/sequence/utils/edit.mjs +2 -3
  19. package/dist/es/animation/utils/default-transitions.mjs +1 -1
  20. package/dist/es/animation/utils/stagger.mjs +1 -1
  21. package/dist/es/components/AnimatePresence/PresenceChild.mjs +26 -23
  22. package/dist/es/components/Reorder/utils/check-reorder.mjs +1 -1
  23. package/dist/es/dom.mjs +2 -18
  24. package/dist/es/gestures/drag/VisualElementDragControls.mjs +1 -3
  25. package/dist/es/gestures/drag/utils/constraints.mjs +2 -3
  26. package/dist/es/gestures/focus.mjs +1 -1
  27. package/dist/es/gestures/pan/PanSession.mjs +1 -2
  28. package/dist/es/index.mjs +3 -24
  29. package/dist/es/motion/utils/is-forced-motion-value.mjs +1 -1
  30. package/dist/es/projection/animation/mix-values.mjs +2 -4
  31. package/dist/es/projection/geometry/delta-apply.mjs +1 -1
  32. package/dist/es/projection/geometry/delta-calc.mjs +1 -1
  33. package/dist/es/projection/geometry/delta-remove.mjs +1 -2
  34. package/dist/es/projection/node/create-projection-node.mjs +3 -7
  35. package/dist/es/projection/styles/scale-border-radius.mjs +1 -1
  36. package/dist/es/projection/styles/scale-box-shadow.mjs +1 -2
  37. package/dist/es/projection/styles/scale-correction.mjs +1 -1
  38. package/dist/es/projection.mjs +1 -3
  39. package/dist/es/render/VisualElement.mjs +2 -9
  40. package/dist/es/render/dom/DOMVisualElement.mjs +1 -1
  41. package/dist/es/render/dom/scroll/attach-animation.mjs +17 -0
  42. package/dist/es/render/dom/scroll/attach-function.mjs +23 -0
  43. package/dist/es/render/dom/scroll/index.mjs +6 -82
  44. package/dist/es/render/dom/scroll/offsets/index.mjs +2 -3
  45. package/dist/es/render/dom/scroll/utils/get-timeline.mjs +29 -0
  46. package/dist/es/render/html/HTMLVisualElement.mjs +1 -3
  47. package/dist/es/render/html/utils/build-styles.mjs +1 -4
  48. package/dist/es/render/html/utils/build-transform.mjs +1 -3
  49. package/dist/es/render/svg/SVGVisualElement.mjs +1 -3
  50. package/dist/es/render/svg/config-motion.mjs +1 -2
  51. package/dist/es/render/svg/utils/path.mjs +1 -1
  52. package/dist/es/render/svg/utils/scrape-motion-values.mjs +1 -1
  53. package/dist/es/render/svg/utils/transform-origin.mjs +1 -1
  54. package/dist/es/render/utils/motion-values.mjs +1 -1
  55. package/dist/es/utils/delay.mjs +1 -1
  56. package/dist/es/utils/transform.mjs +1 -1
  57. package/dist/es/utils/use-cycle.mjs +1 -1
  58. package/dist/es/utils/use-instant-transition.mjs +4 -4
  59. package/dist/es/value/use-spring.mjs +2 -3
  60. package/dist/es/value/use-will-change/get-will-change-name.mjs +1 -2
  61. package/dist/framer-motion.dev.js +3881 -3419
  62. package/dist/framer-motion.js +1 -1
  63. package/dist/m.d.ts +3 -50
  64. package/dist/mini.js +1 -1
  65. package/dist/size-rollup-animate.js +1 -1
  66. package/dist/size-rollup-dom-animation-assets.js +1 -1
  67. package/dist/size-rollup-dom-animation.js +1 -1
  68. package/dist/size-rollup-dom-max-assets.js +1 -1
  69. package/dist/size-rollup-dom-max.js +1 -1
  70. package/dist/size-rollup-m.js +1 -1
  71. package/dist/size-rollup-motion.js +1 -1
  72. package/dist/size-rollup-scroll.js +1 -1
  73. package/dist/size-rollup-waapi-animate.js +1 -1
  74. package/dist/types/client.d.ts +4 -3
  75. package/dist/types/index.d.ts +56 -351
  76. package/dist/{types.d-B50aGbjN.d.ts → types.d-B1Voffvi.d.ts} +3 -138
  77. package/package.json +9 -9
  78. package/dist/es/animation/animators/AcceleratedAnimation.mjs +0 -319
  79. package/dist/es/animation/animators/BaseAnimation.mjs +0 -120
  80. package/dist/es/animation/animators/MainThreadAnimation.mjs +0 -394
  81. package/dist/es/animation/animators/drivers/driver-frameloop.mjs +0 -16
  82. package/dist/es/animation/animators/utils/accelerated-values.mjs +0 -14
  83. package/dist/es/animation/animators/utils/can-animate.mjs +0 -42
  84. package/dist/es/animation/animators/waapi/utils/supports-waapi.mjs +0 -5
  85. package/dist/es/animation/generators/inertia.mjs +0 -87
  86. package/dist/es/animation/generators/keyframes.mjs +0 -51
  87. package/dist/es/animation/generators/spring/defaults.mjs +0 -27
  88. package/dist/es/animation/generators/spring/find.mjs +0 -85
  89. package/dist/es/animation/generators/spring/index.mjs +0 -174
  90. package/dist/es/animation/generators/utils/velocity.mjs +0 -9
  91. package/dist/es/animation/utils/is-animatable.mjs +0 -30
  92. package/dist/es/animation/utils/is-none.mjs +0 -15
  93. package/dist/es/easing/anticipate.mjs +0 -5
  94. package/dist/es/easing/back.mjs +0 -9
  95. package/dist/es/easing/circ.mjs +0 -8
  96. package/dist/es/easing/cubic-bezier.mjs +0 -51
  97. package/dist/es/easing/ease.mjs +0 -7
  98. package/dist/es/easing/modifiers/mirror.mjs +0 -5
  99. package/dist/es/easing/modifiers/reverse.mjs +0 -5
  100. package/dist/es/easing/steps.mjs +0 -15
  101. package/dist/es/easing/utils/get-easing-for-segment.mjs +0 -8
  102. package/dist/es/easing/utils/is-easing-array.mjs +0 -5
  103. package/dist/es/easing/utils/map.mjs +0 -37
  104. package/dist/es/render/dom/DOMKeyframesResolver.mjs +0 -130
  105. package/dist/es/render/dom/scroll/observe.mjs +0 -18
  106. package/dist/es/render/dom/utils/css-variables-conversion.mjs +0 -42
  107. package/dist/es/render/dom/utils/is-css-variable.mjs +0 -15
  108. package/dist/es/render/dom/utils/unit-conversion.mjs +0 -36
  109. package/dist/es/render/dom/value-types/animatable-none.mjs +0 -15
  110. package/dist/es/render/dom/value-types/defaults.mjs +0 -30
  111. package/dist/es/render/dom/value-types/dimensions.mjs +0 -15
  112. package/dist/es/render/dom/value-types/find.mjs +0 -15
  113. package/dist/es/render/dom/value-types/get-as-type.mjs +0 -10
  114. package/dist/es/render/dom/value-types/number-browser.mjs +0 -41
  115. package/dist/es/render/dom/value-types/number.mjs +0 -18
  116. package/dist/es/render/dom/value-types/test.mjs +0 -6
  117. package/dist/es/render/dom/value-types/transform.mjs +0 -31
  118. package/dist/es/render/dom/value-types/type-auto.mjs +0 -9
  119. package/dist/es/render/dom/value-types/type-int.mjs +0 -8
  120. package/dist/es/render/html/utils/keys-position.mjs +0 -13
  121. package/dist/es/render/html/utils/keys-transform.mjs +0 -28
  122. package/dist/es/render/html/utils/make-none-animatable.mjs +0 -30
  123. package/dist/es/render/html/utils/parse-transform.mjs +0 -83
  124. package/dist/es/render/utils/KeyframesResolver.mjs +0 -163
  125. package/dist/es/utils/clamp.mjs +0 -9
  126. package/dist/es/utils/hsla-to-rgba.mjs +0 -42
  127. package/dist/es/utils/interpolate.mjs +0 -76
  128. package/dist/es/utils/is-numerical-string.mjs +0 -6
  129. package/dist/es/utils/is-zero-value-string.mjs +0 -6
  130. package/dist/es/utils/mix/color.mjs +0 -47
  131. package/dist/es/utils/mix/complex.mjs +0 -93
  132. package/dist/es/utils/mix/immediate.mjs +0 -5
  133. package/dist/es/utils/mix/index.mjs +0 -14
  134. package/dist/es/utils/mix/number.mjs +0 -26
  135. package/dist/es/utils/mix/visibility.mjs +0 -16
  136. package/dist/es/utils/offsets/default.mjs +0 -9
  137. package/dist/es/utils/offsets/fill.mjs +0 -12
  138. package/dist/es/utils/offsets/time.mjs +0 -5
  139. package/dist/es/utils/pipe.mjs +0 -11
  140. package/dist/es/utils/use-instant-transition-state.mjs +0 -5
  141. package/dist/es/utils/wrap.mjs +0 -6
  142. package/dist/es/value/types/color/hex.mjs +0 -40
  143. package/dist/es/value/types/color/hsla.mjs +0 -22
  144. package/dist/es/value/types/color/index.mjs +0 -27
  145. package/dist/es/value/types/color/rgba.mjs +0 -25
  146. package/dist/es/value/types/color/utils.mjs +0 -29
  147. package/dist/es/value/types/complex/filter.mjs +0 -30
  148. package/dist/es/value/types/complex/index.mjs +0 -91
  149. package/dist/es/value/types/numbers/index.mjs +0 -17
  150. package/dist/es/value/types/numbers/units.mjs +0 -17
  151. package/dist/es/value/types/utils/color-regex.mjs +0 -3
  152. package/dist/es/value/types/utils/float-regex.mjs +0 -3
  153. package/dist/es/value/types/utils/is-nullish.mjs +0 -5
  154. package/dist/es/value/types/utils/sanitize.mjs +0 -5
  155. package/dist/es/value/types/utils/single-color-regex.mjs +0 -3
@@ -107,31 +107,6 @@ function isPresent(context) {
107
107
  return context === null ? true : context.isPresent;
108
108
  }
109
109
 
110
- /*
111
- Value in range from progress
112
-
113
- Given a lower limit and an upper limit, we return the value within
114
- that range as expressed by progress (usually a number from 0 to 1)
115
-
116
- So progress = 0.5 would change
117
-
118
- from -------- to
119
-
120
- to
121
-
122
- from ---- to
123
-
124
- E.g. from = 10, to = 20, progress = 0.5 => 15
125
-
126
- @param [number]: Lower limit of range
127
- @param [number]: Upper limit of range
128
- @param [number]: The progress between lower and upper limits expressed 0-1
129
- @return [number]: Value as calculated from progress within range (not limited within range)
130
- */
131
- const mixNumber$1 = (from, to, progress) => {
132
- return from + (to - from) * progress;
133
- };
134
-
135
110
  const SCALE_PRECISION = 0.0001;
136
111
  const SCALE_MIN = 1 - SCALE_PRECISION;
137
112
  const SCALE_MAX = 1 + SCALE_PRECISION;
@@ -146,10 +121,10 @@ function isNear(value, target, maxDistance) {
146
121
  }
147
122
  function calcAxisDelta(delta, source, target, origin = 0.5) {
148
123
  delta.origin = origin;
149
- delta.originPoint = mixNumber$1(source.min, source.max, delta.origin);
124
+ delta.originPoint = motionDom.mixNumber(source.min, source.max, delta.origin);
150
125
  delta.scale = calcLength(target) / calcLength(source);
151
126
  delta.translate =
152
- mixNumber$1(target.min, target.max, delta.origin) - delta.originPoint;
127
+ motionDom.mixNumber(target.min, target.max, delta.origin) - delta.originPoint;
153
128
  if ((delta.scale >= SCALE_MIN && delta.scale <= SCALE_MAX) ||
154
129
  isNaN(delta.scale)) {
155
130
  delta.scale = 1.0;
@@ -158,2674 +133,40 @@ function calcAxisDelta(delta, source, target, origin = 0.5) {
158
133
  delta.translate <= TRANSLATE_MAX) ||
159
134
  isNaN(delta.translate)) {
160
135
  delta.translate = 0.0;
161
- }
162
- }
163
- function calcBoxDelta(delta, source, target, origin) {
164
- calcAxisDelta(delta.x, source.x, target.x, origin ? origin.originX : undefined);
165
- calcAxisDelta(delta.y, source.y, target.y, origin ? origin.originY : undefined);
166
- }
167
- function calcRelativeAxis(target, relative, parent) {
168
- target.min = parent.min + relative.min;
169
- target.max = target.min + calcLength(relative);
170
- }
171
- function calcRelativeBox(target, relative, parent) {
172
- calcRelativeAxis(target.x, relative.x, parent.x);
173
- calcRelativeAxis(target.y, relative.y, parent.y);
174
- }
175
- function calcRelativeAxisPosition(target, layout, parent) {
176
- target.min = layout.min - parent.min;
177
- target.max = target.min + calcLength(layout);
178
- }
179
- function calcRelativePosition(target, layout, parent) {
180
- calcRelativeAxisPosition(target.x, layout.x, parent.x);
181
- calcRelativeAxisPosition(target.y, layout.y, parent.y);
182
- }
183
-
184
- const isMotionValue = (value) => Boolean(value && value.getVelocity);
185
-
186
- const instantAnimationState = {
187
- current: false,
188
- };
189
-
190
- /*
191
- Bezier function generator
192
- This has been modified from Gaëtan Renaudeau's BezierEasing
193
- https://github.com/gre/bezier-easing/blob/master/src/index.js
194
- https://github.com/gre/bezier-easing/blob/master/LICENSE
195
-
196
- I've removed the newtonRaphsonIterate algo because in benchmarking it
197
- wasn't noticiably faster than binarySubdivision, indeed removing it
198
- usually improved times, depending on the curve.
199
- I also removed the lookup table, as for the added bundle size and loop we're
200
- only cutting ~4 or so subdivision iterations. I bumped the max iterations up
201
- to 12 to compensate and this still tended to be faster for no perceivable
202
- loss in accuracy.
203
- Usage
204
- const easeOut = cubicBezier(.17,.67,.83,.67);
205
- const x = easeOut(0.5); // returns 0.627...
206
- */
207
- // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
208
- const calcBezier = (t, a1, a2) => (((1.0 - 3.0 * a2 + 3.0 * a1) * t + (3.0 * a2 - 6.0 * a1)) * t + 3.0 * a1) *
209
- t;
210
- const subdivisionPrecision = 0.0000001;
211
- const subdivisionMaxIterations = 12;
212
- function binarySubdivide(x, lowerBound, upperBound, mX1, mX2) {
213
- let currentX;
214
- let currentT;
215
- let i = 0;
216
- do {
217
- currentT = lowerBound + (upperBound - lowerBound) / 2.0;
218
- currentX = calcBezier(currentT, mX1, mX2) - x;
219
- if (currentX > 0.0) {
220
- upperBound = currentT;
221
- }
222
- else {
223
- lowerBound = currentT;
224
- }
225
- } while (Math.abs(currentX) > subdivisionPrecision &&
226
- ++i < subdivisionMaxIterations);
227
- return currentT;
228
- }
229
- function cubicBezier(mX1, mY1, mX2, mY2) {
230
- // If this is a linear gradient, return linear easing
231
- if (mX1 === mY1 && mX2 === mY2)
232
- return motionUtils.noop;
233
- const getTForX = (aX) => binarySubdivide(aX, 0, 1, mX1, mX2);
234
- // If animation is at start/end, return t without easing
235
- return (t) => t === 0 || t === 1 ? t : calcBezier(getTForX(t), mY1, mY2);
236
- }
237
-
238
- // Accepts an easing function and returns a new one that outputs mirrored values for
239
- // the second half of the animation. Turns easeIn into easeInOut.
240
- const mirrorEasing = (easing) => (p) => p <= 0.5 ? easing(2 * p) / 2 : (2 - easing(2 * (1 - p))) / 2;
241
-
242
- // Accepts an easing function and returns a new one that outputs reversed values.
243
- // Turns easeIn into easeOut.
244
- const reverseEasing = (easing) => (p) => 1 - easing(1 - p);
245
-
246
- const backOut = /*@__PURE__*/ cubicBezier(0.33, 1.53, 0.69, 0.99);
247
- const backIn = /*@__PURE__*/ reverseEasing(backOut);
248
- const backInOut = /*@__PURE__*/ mirrorEasing(backIn);
249
-
250
- const anticipate = (p) => (p *= 2) < 1 ? 0.5 * backIn(p) : 0.5 * (2 - Math.pow(2, -10 * (p - 1)));
251
-
252
- const circIn = (p) => 1 - Math.sin(Math.acos(p));
253
- const circOut = reverseEasing(circIn);
254
- const circInOut = mirrorEasing(circIn);
255
-
256
- /**
257
- * Check if the value is a zero value string like "0px" or "0%"
258
- */
259
- const isZeroValueString = (v) => /^0[^.\s]+$/u.test(v);
260
-
261
- function isNone(value) {
262
- if (typeof value === "number") {
263
- return value === 0;
264
- }
265
- else if (value !== null) {
266
- return value === "none" || value === "0" || isZeroValueString(value);
267
- }
268
- else {
269
- return true;
270
- }
271
- }
272
-
273
- /**
274
- * Generate a list of every possible transform key.
275
- */
276
- const transformPropOrder = [
277
- "transformPerspective",
278
- "x",
279
- "y",
280
- "z",
281
- "translateX",
282
- "translateY",
283
- "translateZ",
284
- "scale",
285
- "scaleX",
286
- "scaleY",
287
- "rotate",
288
- "rotateX",
289
- "rotateY",
290
- "rotateZ",
291
- "skew",
292
- "skewX",
293
- "skewY",
294
- ];
295
- /**
296
- * A quick lookup for transform props.
297
- */
298
- const transformProps = new Set(transformPropOrder);
299
-
300
- const positionalKeys = new Set([
301
- "width",
302
- "height",
303
- "top",
304
- "left",
305
- "right",
306
- "bottom",
307
- ...transformPropOrder,
308
- ]);
309
-
310
- const clamp = (min, max, v) => {
311
- if (v > max)
312
- return max;
313
- if (v < min)
314
- return min;
315
- return v;
316
- };
317
-
318
- const number = {
319
- test: (v) => typeof v === "number",
320
- parse: parseFloat,
321
- transform: (v) => v,
322
- };
323
- const alpha = {
324
- ...number,
325
- transform: (v) => clamp(0, 1, v),
326
- };
327
- const scale = {
328
- ...number,
329
- default: 1,
330
- };
331
-
332
- // If this number is a decimal, make it just five decimal places
333
- // to avoid exponents
334
- const sanitize = (v) => Math.round(v * 100000) / 100000;
335
-
336
- const floatRegex = /-?(?:\d+(?:\.\d+)?|\.\d+)/gu;
337
-
338
- function isNullish(v) {
339
- return v == null;
340
- }
341
-
342
- const singleColorRegex = /^(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))$/iu;
343
-
344
- /**
345
- * Returns true if the provided string is a color, ie rgba(0,0,0,0) or #000,
346
- * but false if a number or multiple colors
347
- */
348
- const isColorString = (type, testProp) => (v) => {
349
- return Boolean((typeof v === "string" &&
350
- singleColorRegex.test(v) &&
351
- v.startsWith(type)) ||
352
- (testProp &&
353
- !isNullish(v) &&
354
- Object.prototype.hasOwnProperty.call(v, testProp)));
355
- };
356
- const splitColor = (aName, bName, cName) => (v) => {
357
- if (typeof v !== "string")
358
- return v;
359
- const [a, b, c, alpha] = v.match(floatRegex);
360
- return {
361
- [aName]: parseFloat(a),
362
- [bName]: parseFloat(b),
363
- [cName]: parseFloat(c),
364
- alpha: alpha !== undefined ? parseFloat(alpha) : 1,
365
- };
366
- };
367
-
368
- const clampRgbUnit = (v) => clamp(0, 255, v);
369
- const rgbUnit = {
370
- ...number,
371
- transform: (v) => Math.round(clampRgbUnit(v)),
372
- };
373
- const rgba = {
374
- test: /*@__PURE__*/ isColorString("rgb", "red"),
375
- parse: /*@__PURE__*/ splitColor("red", "green", "blue"),
376
- transform: ({ red, green, blue, alpha: alpha$1 = 1 }) => "rgba(" +
377
- rgbUnit.transform(red) +
378
- ", " +
379
- rgbUnit.transform(green) +
380
- ", " +
381
- rgbUnit.transform(blue) +
382
- ", " +
383
- sanitize(alpha.transform(alpha$1)) +
384
- ")",
385
- };
386
-
387
- function parseHex(v) {
388
- let r = "";
389
- let g = "";
390
- let b = "";
391
- let a = "";
392
- // If we have 6 characters, ie #FF0000
393
- if (v.length > 5) {
394
- r = v.substring(1, 3);
395
- g = v.substring(3, 5);
396
- b = v.substring(5, 7);
397
- a = v.substring(7, 9);
398
- // Or we have 3 characters, ie #F00
399
- }
400
- else {
401
- r = v.substring(1, 2);
402
- g = v.substring(2, 3);
403
- b = v.substring(3, 4);
404
- a = v.substring(4, 5);
405
- r += r;
406
- g += g;
407
- b += b;
408
- a += a;
409
- }
410
- return {
411
- red: parseInt(r, 16),
412
- green: parseInt(g, 16),
413
- blue: parseInt(b, 16),
414
- alpha: a ? parseInt(a, 16) / 255 : 1,
415
- };
416
- }
417
- const hex = {
418
- test: /*@__PURE__*/ isColorString("#"),
419
- parse: parseHex,
420
- transform: rgba.transform,
421
- };
422
-
423
- const createUnitType = (unit) => ({
424
- test: (v) => typeof v === "string" && v.endsWith(unit) && v.split(" ").length === 1,
425
- parse: parseFloat,
426
- transform: (v) => `${v}${unit}`,
427
- });
428
- const degrees = /*@__PURE__*/ createUnitType("deg");
429
- const percent = /*@__PURE__*/ createUnitType("%");
430
- const px = /*@__PURE__*/ createUnitType("px");
431
- const vh = /*@__PURE__*/ createUnitType("vh");
432
- const vw = /*@__PURE__*/ createUnitType("vw");
433
- const progressPercentage = {
434
- ...percent,
435
- parse: (v) => percent.parse(v) / 100,
436
- transform: (v) => percent.transform(v * 100),
437
- };
438
-
439
- const hsla = {
440
- test: /*@__PURE__*/ isColorString("hsl", "hue"),
441
- parse: /*@__PURE__*/ splitColor("hue", "saturation", "lightness"),
442
- transform: ({ hue, saturation, lightness, alpha: alpha$1 = 1 }) => {
443
- return ("hsla(" +
444
- Math.round(hue) +
445
- ", " +
446
- percent.transform(sanitize(saturation)) +
447
- ", " +
448
- percent.transform(sanitize(lightness)) +
449
- ", " +
450
- sanitize(alpha.transform(alpha$1)) +
451
- ")");
452
- },
453
- };
454
-
455
- const color = {
456
- test: (v) => rgba.test(v) || hex.test(v) || hsla.test(v),
457
- parse: (v) => {
458
- if (rgba.test(v)) {
459
- return rgba.parse(v);
460
- }
461
- else if (hsla.test(v)) {
462
- return hsla.parse(v);
463
- }
464
- else {
465
- return hex.parse(v);
466
- }
467
- },
468
- transform: (v) => {
469
- return typeof v === "string"
470
- ? v
471
- : v.hasOwnProperty("red")
472
- ? rgba.transform(v)
473
- : hsla.transform(v);
474
- },
475
- };
476
-
477
- const colorRegex = /(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))/giu;
478
-
479
- function test(v) {
480
- return (isNaN(v) &&
481
- typeof v === "string" &&
482
- (v.match(floatRegex)?.length || 0) +
483
- (v.match(colorRegex)?.length || 0) >
484
- 0);
485
- }
486
- const NUMBER_TOKEN = "number";
487
- const COLOR_TOKEN = "color";
488
- const VAR_TOKEN = "var";
489
- const VAR_FUNCTION_TOKEN = "var(";
490
- const SPLIT_TOKEN = "${}";
491
- // this regex consists of the `singleCssVariableRegex|rgbHSLValueRegex|digitRegex`
492
- const complexRegex = /var\s*\(\s*--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)|#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\)|-?(?:\d+(?:\.\d+)?|\.\d+)/giu;
493
- function analyseComplexValue(value) {
494
- const originalValue = value.toString();
495
- const values = [];
496
- const indexes = {
497
- color: [],
498
- number: [],
499
- var: [],
500
- };
501
- const types = [];
502
- let i = 0;
503
- const tokenised = originalValue.replace(complexRegex, (parsedValue) => {
504
- if (color.test(parsedValue)) {
505
- indexes.color.push(i);
506
- types.push(COLOR_TOKEN);
507
- values.push(color.parse(parsedValue));
508
- }
509
- else if (parsedValue.startsWith(VAR_FUNCTION_TOKEN)) {
510
- indexes.var.push(i);
511
- types.push(VAR_TOKEN);
512
- values.push(parsedValue);
513
- }
514
- else {
515
- indexes.number.push(i);
516
- types.push(NUMBER_TOKEN);
517
- values.push(parseFloat(parsedValue));
518
- }
519
- ++i;
520
- return SPLIT_TOKEN;
521
- });
522
- const split = tokenised.split(SPLIT_TOKEN);
523
- return { values, split, indexes, types };
524
- }
525
- function parseComplexValue(v) {
526
- return analyseComplexValue(v).values;
527
- }
528
- function createTransformer(source) {
529
- const { split, types } = analyseComplexValue(source);
530
- const numSections = split.length;
531
- return (v) => {
532
- let output = "";
533
- for (let i = 0; i < numSections; i++) {
534
- output += split[i];
535
- if (v[i] !== undefined) {
536
- const type = types[i];
537
- if (type === NUMBER_TOKEN) {
538
- output += sanitize(v[i]);
539
- }
540
- else if (type === COLOR_TOKEN) {
541
- output += color.transform(v[i]);
542
- }
543
- else {
544
- output += v[i];
545
- }
546
- }
547
- }
548
- return output;
549
- };
550
- }
551
- const convertNumbersToZero = (v) => typeof v === "number" ? 0 : v;
552
- function getAnimatableNone$1(v) {
553
- const parsed = parseComplexValue(v);
554
- const transformer = createTransformer(v);
555
- return transformer(parsed.map(convertNumbersToZero));
556
- }
557
- const complex = {
558
- test,
559
- parse: parseComplexValue,
560
- createTransformer,
561
- getAnimatableNone: getAnimatableNone$1,
562
- };
563
-
564
- /**
565
- * Properties that should default to 1 or 100%
566
- */
567
- const maxDefaults = new Set(["brightness", "contrast", "saturate", "opacity"]);
568
- function applyDefaultFilter(v) {
569
- const [name, value] = v.slice(0, -1).split("(");
570
- if (name === "drop-shadow")
571
- return v;
572
- const [number] = value.match(floatRegex) || [];
573
- if (!number)
574
- return v;
575
- const unit = value.replace(number, "");
576
- let defaultValue = maxDefaults.has(name) ? 1 : 0;
577
- if (number !== value)
578
- defaultValue *= 100;
579
- return name + "(" + defaultValue + unit + ")";
580
- }
581
- const functionRegex = /\b([a-z-]*)\(.*?\)/gu;
582
- const filter = {
583
- ...complex,
584
- getAnimatableNone: (v) => {
585
- const functions = v.match(functionRegex);
586
- return functions ? functions.map(applyDefaultFilter).join(" ") : v;
587
- },
588
- };
589
-
590
- const browserNumberValueTypes = {
591
- // Border props
592
- borderWidth: px,
593
- borderTopWidth: px,
594
- borderRightWidth: px,
595
- borderBottomWidth: px,
596
- borderLeftWidth: px,
597
- borderRadius: px,
598
- radius: px,
599
- borderTopLeftRadius: px,
600
- borderTopRightRadius: px,
601
- borderBottomRightRadius: px,
602
- borderBottomLeftRadius: px,
603
- // Positioning props
604
- width: px,
605
- maxWidth: px,
606
- height: px,
607
- maxHeight: px,
608
- top: px,
609
- right: px,
610
- bottom: px,
611
- left: px,
612
- // Spacing props
613
- padding: px,
614
- paddingTop: px,
615
- paddingRight: px,
616
- paddingBottom: px,
617
- paddingLeft: px,
618
- margin: px,
619
- marginTop: px,
620
- marginRight: px,
621
- marginBottom: px,
622
- marginLeft: px,
623
- // Misc
624
- backgroundPositionX: px,
625
- backgroundPositionY: px,
626
- };
627
-
628
- const transformValueTypes = {
629
- rotate: degrees,
630
- rotateX: degrees,
631
- rotateY: degrees,
632
- rotateZ: degrees,
633
- scale,
634
- scaleX: scale,
635
- scaleY: scale,
636
- scaleZ: scale,
637
- skew: degrees,
638
- skewX: degrees,
639
- skewY: degrees,
640
- distance: px,
641
- translateX: px,
642
- translateY: px,
643
- translateZ: px,
644
- x: px,
645
- y: px,
646
- z: px,
647
- perspective: px,
648
- transformPerspective: px,
649
- opacity: alpha,
650
- originX: progressPercentage,
651
- originY: progressPercentage,
652
- originZ: px,
653
- };
654
-
655
- const int = {
656
- ...number,
657
- transform: Math.round,
658
- };
659
-
660
- const numberValueTypes = {
661
- ...browserNumberValueTypes,
662
- ...transformValueTypes,
663
- zIndex: int,
664
- size: px,
665
- // SVG
666
- fillOpacity: alpha,
667
- strokeOpacity: alpha,
668
- numOctaves: int,
669
- };
670
-
671
- /**
672
- * A map of default value types for common values
673
- */
674
- const defaultValueTypes = {
675
- ...numberValueTypes,
676
- // Color props
677
- color,
678
- backgroundColor: color,
679
- outlineColor: color,
680
- fill: color,
681
- stroke: color,
682
- // Border props
683
- borderColor: color,
684
- borderTopColor: color,
685
- borderRightColor: color,
686
- borderBottomColor: color,
687
- borderLeftColor: color,
688
- filter,
689
- WebkitFilter: filter,
690
- };
691
- /**
692
- * Gets the default ValueType for the provided value key
693
- */
694
- const getDefaultValueType = (key) => defaultValueTypes[key];
695
-
696
- function getAnimatableNone(key, value) {
697
- let defaultValueType = getDefaultValueType(key);
698
- if (defaultValueType !== filter)
699
- defaultValueType = complex;
700
- // If value is not recognised as animatable, ie "none", create an animatable version origin based on the target
701
- return defaultValueType.getAnimatableNone
702
- ? defaultValueType.getAnimatableNone(value)
703
- : undefined;
704
- }
705
-
706
- /**
707
- * If we encounter keyframes like "none" or "0" and we also have keyframes like
708
- * "#fff" or "200px 200px" we want to find a keyframe to serve as a template for
709
- * the "none" keyframes. In this case "#fff" or "200px 200px" - then these get turned into
710
- * zero equivalents, i.e. "#fff0" or "0px 0px".
711
- */
712
- const invalidTemplates = new Set(["auto", "none", "0"]);
713
- function makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, name) {
714
- let i = 0;
715
- let animatableTemplate = undefined;
716
- while (i < unresolvedKeyframes.length && !animatableTemplate) {
717
- const keyframe = unresolvedKeyframes[i];
718
- if (typeof keyframe === "string" &&
719
- !invalidTemplates.has(keyframe) &&
720
- analyseComplexValue(keyframe).values.length) {
721
- animatableTemplate = unresolvedKeyframes[i];
722
- }
723
- i++;
724
- }
725
- if (animatableTemplate && name) {
726
- for (const noneIndex of noneKeyframeIndexes) {
727
- unresolvedKeyframes[noneIndex] = getAnimatableNone(name, animatableTemplate);
728
- }
729
- }
730
- }
731
-
732
- const radToDeg = (rad) => (rad * 180) / Math.PI;
733
- const rotate = (v) => {
734
- const angle = radToDeg(Math.atan2(v[1], v[0]));
735
- return rebaseAngle(angle);
736
- };
737
- const matrix2dParsers = {
738
- x: 4,
739
- y: 5,
740
- translateX: 4,
741
- translateY: 5,
742
- scaleX: 0,
743
- scaleY: 3,
744
- scale: (v) => (Math.abs(v[0]) + Math.abs(v[3])) / 2,
745
- rotate,
746
- rotateZ: rotate,
747
- skewX: (v) => radToDeg(Math.atan(v[1])),
748
- skewY: (v) => radToDeg(Math.atan(v[2])),
749
- skew: (v) => (Math.abs(v[1]) + Math.abs(v[2])) / 2,
750
- };
751
- const rebaseAngle = (angle) => {
752
- angle = angle % 360;
753
- if (angle < 0)
754
- angle += 360;
755
- return angle;
756
- };
757
- const rotateZ = rotate;
758
- const scaleX = (v) => Math.sqrt(v[0] * v[0] + v[1] * v[1]);
759
- const scaleY = (v) => Math.sqrt(v[4] * v[4] + v[5] * v[5]);
760
- const matrix3dParsers = {
761
- x: 12,
762
- y: 13,
763
- z: 14,
764
- translateX: 12,
765
- translateY: 13,
766
- translateZ: 14,
767
- scaleX,
768
- scaleY,
769
- scale: (v) => (scaleX(v) + scaleY(v)) / 2,
770
- rotateX: (v) => rebaseAngle(radToDeg(Math.atan2(v[6], v[5]))),
771
- rotateY: (v) => rebaseAngle(radToDeg(Math.atan2(-v[2], v[0]))),
772
- rotateZ,
773
- rotate: rotateZ,
774
- skewX: (v) => radToDeg(Math.atan(v[4])),
775
- skewY: (v) => radToDeg(Math.atan(v[1])),
776
- skew: (v) => (Math.abs(v[1]) + Math.abs(v[4])) / 2,
777
- };
778
- function defaultTransformValue(name) {
779
- return name.includes("scale") ? 1 : 0;
780
- }
781
- function parseValueFromTransform(transform, name) {
782
- if (!transform || transform === "none") {
783
- return defaultTransformValue(name);
784
- }
785
- const matrix3dMatch = transform.match(/^matrix3d\(([-\d.e\s,]+)\)$/u);
786
- let parsers;
787
- let match;
788
- if (matrix3dMatch) {
789
- parsers = matrix3dParsers;
790
- match = matrix3dMatch;
791
- }
792
- else {
793
- const matrix2dMatch = transform.match(/^matrix\(([-\d.e\s,]+)\)$/u);
794
- parsers = matrix2dParsers;
795
- match = matrix2dMatch;
796
- }
797
- if (!match) {
798
- return defaultTransformValue(name);
799
- }
800
- const valueParser = parsers[name];
801
- const values = match[1].split(",").map(convertTransformToNumber);
802
- return typeof valueParser === "function"
803
- ? valueParser(values)
804
- : values[valueParser];
805
- }
806
- const readTransformValue = (instance, name) => {
807
- const { transform = "none" } = getComputedStyle(instance);
808
- return parseValueFromTransform(transform, name);
809
- };
810
- function convertTransformToNumber(value) {
811
- return parseFloat(value.trim());
812
- }
813
-
814
- const isNumOrPxType = (v) => v === number || v === px;
815
- const transformKeys = new Set(["x", "y", "z"]);
816
- const nonTranslationalTransformKeys = transformPropOrder.filter((key) => !transformKeys.has(key));
817
- function removeNonTranslationalTransform(visualElement) {
818
- const removedTransforms = [];
819
- nonTranslationalTransformKeys.forEach((key) => {
820
- const value = visualElement.getValue(key);
821
- if (value !== undefined) {
822
- removedTransforms.push([key, value.get()]);
823
- value.set(key.startsWith("scale") ? 1 : 0);
824
- }
825
- });
826
- return removedTransforms;
827
- }
828
- const positionalValues = {
829
- // Dimensions
830
- width: ({ x }, { paddingLeft = "0", paddingRight = "0" }) => x.max - x.min - parseFloat(paddingLeft) - parseFloat(paddingRight),
831
- height: ({ y }, { paddingTop = "0", paddingBottom = "0" }) => y.max - y.min - parseFloat(paddingTop) - parseFloat(paddingBottom),
832
- top: (_bbox, { top }) => parseFloat(top),
833
- left: (_bbox, { left }) => parseFloat(left),
834
- bottom: ({ y }, { top }) => parseFloat(top) + (y.max - y.min),
835
- right: ({ x }, { left }) => parseFloat(left) + (x.max - x.min),
836
- // Transform
837
- x: (_bbox, { transform }) => parseValueFromTransform(transform, "x"),
838
- y: (_bbox, { transform }) => parseValueFromTransform(transform, "y"),
839
- };
840
- // Alias translate longform names
841
- positionalValues.translateX = positionalValues.x;
842
- positionalValues.translateY = positionalValues.y;
843
-
844
- const toResolve = new Set();
845
- let isScheduled = false;
846
- let anyNeedsMeasurement = false;
847
- function measureAllKeyframes() {
848
- if (anyNeedsMeasurement) {
849
- const resolversToMeasure = Array.from(toResolve).filter((resolver) => resolver.needsMeasurement);
850
- const elementsToMeasure = new Set(resolversToMeasure.map((resolver) => resolver.element));
851
- const transformsToRestore = new Map();
852
- /**
853
- * Write pass
854
- * If we're measuring elements we want to remove bounding box-changing transforms.
855
- */
856
- elementsToMeasure.forEach((element) => {
857
- const removedTransforms = removeNonTranslationalTransform(element);
858
- if (!removedTransforms.length)
859
- return;
860
- transformsToRestore.set(element, removedTransforms);
861
- element.render();
862
- });
863
- // Read
864
- resolversToMeasure.forEach((resolver) => resolver.measureInitialState());
865
- // Write
866
- elementsToMeasure.forEach((element) => {
867
- element.render();
868
- const restore = transformsToRestore.get(element);
869
- if (restore) {
870
- restore.forEach(([key, value]) => {
871
- element.getValue(key)?.set(value);
872
- });
873
- }
874
- });
875
- // Read
876
- resolversToMeasure.forEach((resolver) => resolver.measureEndState());
877
- // Write
878
- resolversToMeasure.forEach((resolver) => {
879
- if (resolver.suspendedScrollY !== undefined) {
880
- window.scrollTo(0, resolver.suspendedScrollY);
881
- }
882
- });
883
- }
884
- anyNeedsMeasurement = false;
885
- isScheduled = false;
886
- toResolve.forEach((resolver) => resolver.complete());
887
- toResolve.clear();
888
- }
889
- function readAllKeyframes() {
890
- toResolve.forEach((resolver) => {
891
- resolver.readKeyframes();
892
- if (resolver.needsMeasurement) {
893
- anyNeedsMeasurement = true;
894
- }
895
- });
896
- }
897
- function flushKeyframeResolvers() {
898
- readAllKeyframes();
899
- measureAllKeyframes();
900
- }
901
- class KeyframeResolver {
902
- constructor(unresolvedKeyframes, onComplete, name, motionValue, element, isAsync = false) {
903
- /**
904
- * Track whether this resolver has completed. Once complete, it never
905
- * needs to attempt keyframe resolution again.
906
- */
907
- this.isComplete = false;
908
- /**
909
- * Track whether this resolver is async. If it is, it'll be added to the
910
- * resolver queue and flushed in the next frame. Resolvers that aren't going
911
- * to trigger read/write thrashing don't need to be async.
912
- */
913
- this.isAsync = false;
914
- /**
915
- * Track whether this resolver needs to perform a measurement
916
- * to resolve its keyframes.
917
- */
918
- this.needsMeasurement = false;
919
- /**
920
- * Track whether this resolver is currently scheduled to resolve
921
- * to allow it to be cancelled and resumed externally.
922
- */
923
- this.isScheduled = false;
924
- this.unresolvedKeyframes = [...unresolvedKeyframes];
925
- this.onComplete = onComplete;
926
- this.name = name;
927
- this.motionValue = motionValue;
928
- this.element = element;
929
- this.isAsync = isAsync;
930
- }
931
- scheduleResolve() {
932
- this.isScheduled = true;
933
- if (this.isAsync) {
934
- toResolve.add(this);
935
- if (!isScheduled) {
936
- isScheduled = true;
937
- motionDom.frame.read(readAllKeyframes);
938
- motionDom.frame.resolveKeyframes(measureAllKeyframes);
939
- }
940
- }
941
- else {
942
- this.readKeyframes();
943
- this.complete();
944
- }
945
- }
946
- readKeyframes() {
947
- const { unresolvedKeyframes, name, element, motionValue } = this;
948
- /**
949
- * If a keyframe is null, we hydrate it either by reading it from
950
- * the instance, or propagating from previous keyframes.
951
- */
952
- for (let i = 0; i < unresolvedKeyframes.length; i++) {
953
- if (unresolvedKeyframes[i] === null) {
954
- /**
955
- * If the first keyframe is null, we need to find its value by sampling the element
956
- */
957
- if (i === 0) {
958
- const currentValue = motionValue?.get();
959
- const finalKeyframe = unresolvedKeyframes[unresolvedKeyframes.length - 1];
960
- if (currentValue !== undefined) {
961
- unresolvedKeyframes[0] = currentValue;
962
- }
963
- else if (element && name) {
964
- const valueAsRead = element.readValue(name, finalKeyframe);
965
- if (valueAsRead !== undefined && valueAsRead !== null) {
966
- unresolvedKeyframes[0] = valueAsRead;
967
- }
968
- }
969
- if (unresolvedKeyframes[0] === undefined) {
970
- unresolvedKeyframes[0] = finalKeyframe;
971
- }
972
- if (motionValue && currentValue === undefined) {
973
- motionValue.set(unresolvedKeyframes[0]);
974
- }
975
- }
976
- else {
977
- unresolvedKeyframes[i] = unresolvedKeyframes[i - 1];
978
- }
979
- }
980
- }
981
- }
982
- setFinalKeyframe() { }
983
- measureInitialState() { }
984
- renderEndStyles() { }
985
- measureEndState() { }
986
- complete() {
987
- this.isComplete = true;
988
- this.onComplete(this.unresolvedKeyframes, this.finalKeyframe);
989
- toResolve.delete(this);
990
- }
991
- cancel() {
992
- if (!this.isComplete) {
993
- this.isScheduled = false;
994
- toResolve.delete(this);
995
- }
996
- }
997
- resume() {
998
- if (!this.isComplete)
999
- this.scheduleResolve();
1000
- }
1001
- }
1002
-
1003
- /**
1004
- * Check if value is a numerical string, ie a string that is purely a number eg "100" or "-100.1"
1005
- */
1006
- const isNumericalString = (v) => /^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(v);
1007
-
1008
- const checkStringStartsWith = (token) => (key) => typeof key === "string" && key.startsWith(token);
1009
- const isCSSVariableName =
1010
- /*@__PURE__*/ checkStringStartsWith("--");
1011
- const startsAsVariableToken =
1012
- /*@__PURE__*/ checkStringStartsWith("var(--");
1013
- const isCSSVariableToken = (value) => {
1014
- const startsWithToken = startsAsVariableToken(value);
1015
- if (!startsWithToken)
1016
- return false;
1017
- // Ensure any comments are stripped from the value as this can harm performance of the regex.
1018
- return singleCssVariableRegex.test(value.split("/*")[0].trim());
1019
- };
1020
- const singleCssVariableRegex = /var\(--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)$/iu;
1021
-
1022
- /**
1023
- * Parse Framer's special CSS variable format into a CSS token and a fallback.
1024
- *
1025
- * ```
1026
- * `var(--foo, #fff)` => [`--foo`, '#fff']
1027
- * ```
1028
- *
1029
- * @param current
1030
- */
1031
- const splitCSSVariableRegex =
1032
- // eslint-disable-next-line redos-detector/no-unsafe-regex -- false positive, as it can match a lot of words
1033
- /^var\(--(?:([\w-]+)|([\w-]+), ?([a-zA-Z\d ()%#.,-]+))\)/u;
1034
- function parseCSSVariable(current) {
1035
- const match = splitCSSVariableRegex.exec(current);
1036
- if (!match)
1037
- return [,];
1038
- const [, token1, token2, fallback] = match;
1039
- return [`--${token1 ?? token2}`, fallback];
1040
- }
1041
- const maxDepth = 4;
1042
- function getVariableValue(current, element, depth = 1) {
1043
- motionUtils.invariant(depth <= maxDepth, `Max CSS variable fallback depth detected in property "${current}". This may indicate a circular fallback dependency.`);
1044
- const [token, fallback] = parseCSSVariable(current);
1045
- // No CSS variable detected
1046
- if (!token)
1047
- return;
1048
- // Attempt to read this CSS variable off the element
1049
- const resolved = window.getComputedStyle(element).getPropertyValue(token);
1050
- if (resolved) {
1051
- const trimmed = resolved.trim();
1052
- return isNumericalString(trimmed) ? parseFloat(trimmed) : trimmed;
1053
- }
1054
- return isCSSVariableToken(fallback)
1055
- ? getVariableValue(fallback, element, depth + 1)
1056
- : fallback;
1057
- }
1058
-
1059
- /**
1060
- * Tests a provided value against a ValueType
1061
- */
1062
- const testValueType = (v) => (type) => type.test(v);
1063
-
1064
- /**
1065
- * ValueType for "auto"
1066
- */
1067
- const auto = {
1068
- test: (v) => v === "auto",
1069
- parse: (v) => v,
1070
- };
1071
-
1072
- /**
1073
- * A list of value types commonly used for dimensions
1074
- */
1075
- const dimensionValueTypes = [number, px, percent, degrees, vw, vh, auto];
1076
- /**
1077
- * Tests a dimensional value against the list of dimension ValueTypes
1078
- */
1079
- const findDimensionValueType = (v) => dimensionValueTypes.find(testValueType(v));
1080
-
1081
- class DOMKeyframesResolver extends KeyframeResolver {
1082
- constructor(unresolvedKeyframes, onComplete, name, motionValue, element) {
1083
- super(unresolvedKeyframes, onComplete, name, motionValue, element, true);
1084
- }
1085
- readKeyframes() {
1086
- const { unresolvedKeyframes, element, name } = this;
1087
- if (!element || !element.current)
1088
- return;
1089
- super.readKeyframes();
1090
- /**
1091
- * If any keyframe is a CSS variable, we need to find its value by sampling the element
1092
- */
1093
- for (let i = 0; i < unresolvedKeyframes.length; i++) {
1094
- let keyframe = unresolvedKeyframes[i];
1095
- if (typeof keyframe === "string") {
1096
- keyframe = keyframe.trim();
1097
- if (isCSSVariableToken(keyframe)) {
1098
- const resolved = getVariableValue(keyframe, element.current);
1099
- if (resolved !== undefined) {
1100
- unresolvedKeyframes[i] = resolved;
1101
- }
1102
- if (i === unresolvedKeyframes.length - 1) {
1103
- this.finalKeyframe = keyframe;
1104
- }
1105
- }
1106
- }
1107
- }
1108
- /**
1109
- * Resolve "none" values. We do this potentially twice - once before and once after measuring keyframes.
1110
- * This could be seen as inefficient but it's a trade-off to avoid measurements in more situations, which
1111
- * have a far bigger performance impact.
1112
- */
1113
- this.resolveNoneKeyframes();
1114
- /**
1115
- * Check to see if unit type has changed. If so schedule jobs that will
1116
- * temporarily set styles to the destination keyframes.
1117
- * Skip if we have more than two keyframes or this isn't a positional value.
1118
- * TODO: We can throw if there are multiple keyframes and the value type changes.
1119
- */
1120
- if (!positionalKeys.has(name) || unresolvedKeyframes.length !== 2) {
1121
- return;
1122
- }
1123
- const [origin, target] = unresolvedKeyframes;
1124
- const originType = findDimensionValueType(origin);
1125
- const targetType = findDimensionValueType(target);
1126
- /**
1127
- * Either we don't recognise these value types or we can animate between them.
1128
- */
1129
- if (originType === targetType)
1130
- return;
1131
- /**
1132
- * If both values are numbers or pixels, we can animate between them by
1133
- * converting them to numbers.
1134
- */
1135
- if (isNumOrPxType(originType) && isNumOrPxType(targetType)) {
1136
- for (let i = 0; i < unresolvedKeyframes.length; i++) {
1137
- const value = unresolvedKeyframes[i];
1138
- if (typeof value === "string") {
1139
- unresolvedKeyframes[i] = parseFloat(value);
1140
- }
1141
- }
1142
- }
1143
- else {
1144
- /**
1145
- * Else, the only way to resolve this is by measuring the element.
1146
- */
1147
- this.needsMeasurement = true;
1148
- }
1149
- }
1150
- resolveNoneKeyframes() {
1151
- const { unresolvedKeyframes, name } = this;
1152
- const noneKeyframeIndexes = [];
1153
- for (let i = 0; i < unresolvedKeyframes.length; i++) {
1154
- if (isNone(unresolvedKeyframes[i])) {
1155
- noneKeyframeIndexes.push(i);
1156
- }
1157
- }
1158
- if (noneKeyframeIndexes.length) {
1159
- makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, name);
1160
- }
1161
- }
1162
- measureInitialState() {
1163
- const { element, unresolvedKeyframes, name } = this;
1164
- if (!element || !element.current)
1165
- return;
1166
- if (name === "height") {
1167
- this.suspendedScrollY = window.pageYOffset;
1168
- }
1169
- this.measuredOrigin = positionalValues[name](element.measureViewportBox(), window.getComputedStyle(element.current));
1170
- unresolvedKeyframes[0] = this.measuredOrigin;
1171
- // Set final key frame to measure after next render
1172
- const measureKeyframe = unresolvedKeyframes[unresolvedKeyframes.length - 1];
1173
- if (measureKeyframe !== undefined) {
1174
- element.getValue(name, measureKeyframe).jump(measureKeyframe, false);
1175
- }
1176
- }
1177
- measureEndState() {
1178
- const { element, name, unresolvedKeyframes } = this;
1179
- if (!element || !element.current)
1180
- return;
1181
- const value = element.getValue(name);
1182
- value && value.jump(this.measuredOrigin, false);
1183
- const finalKeyframeIndex = unresolvedKeyframes.length - 1;
1184
- const finalKeyframe = unresolvedKeyframes[finalKeyframeIndex];
1185
- unresolvedKeyframes[finalKeyframeIndex] = positionalValues[name](element.measureViewportBox(), window.getComputedStyle(element.current));
1186
- if (finalKeyframe !== null && this.finalKeyframe === undefined) {
1187
- this.finalKeyframe = finalKeyframe;
1188
- }
1189
- // If we removed transform values, reapply them before the next render
1190
- if (this.removedTransforms?.length) {
1191
- this.removedTransforms.forEach(([unsetTransformName, unsetTransformValue]) => {
1192
- element
1193
- .getValue(unsetTransformName)
1194
- .set(unsetTransformValue);
1195
- });
1196
- }
1197
- this.resolveNoneKeyframes();
1198
- }
1199
- }
1200
-
1201
- /**
1202
- * Check if a value is animatable. Examples:
1203
- *
1204
- * ✅: 100, "100px", "#fff"
1205
- * ❌: "block", "url(2.jpg)"
1206
- * @param value
1207
- *
1208
- * @internal
1209
- */
1210
- const isAnimatable = (value, name) => {
1211
- // If the list of keys tat might be non-animatable grows, replace with Set
1212
- if (name === "zIndex")
1213
- return false;
1214
- // If it's a number or a keyframes array, we can animate it. We might at some point
1215
- // need to do a deep isAnimatable check of keyframes, or let Popmotion handle this,
1216
- // but for now lets leave it like this for performance reasons
1217
- if (typeof value === "number" || Array.isArray(value))
1218
- return true;
1219
- if (typeof value === "string" && // It's animatable if we have a string
1220
- (complex.test(value) || value === "0") && // And it contains numbers and/or colors
1221
- !value.startsWith("url(") // Unless it starts with "url("
1222
- ) {
1223
- return true;
1224
- }
1225
- return false;
1226
- };
1227
-
1228
- function hasKeyframesChanged(keyframes) {
1229
- const current = keyframes[0];
1230
- if (keyframes.length === 1)
1231
- return true;
1232
- for (let i = 0; i < keyframes.length; i++) {
1233
- if (keyframes[i] !== current)
1234
- return true;
1235
- }
1236
- }
1237
- function canAnimate(keyframes, name, type, velocity) {
1238
- /**
1239
- * Check if we're able to animate between the start and end keyframes,
1240
- * and throw a warning if we're attempting to animate between one that's
1241
- * animatable and another that isn't.
1242
- */
1243
- const originKeyframe = keyframes[0];
1244
- if (originKeyframe === null)
1245
- return false;
1246
- /**
1247
- * These aren't traditionally animatable but we do support them.
1248
- * In future we could look into making this more generic or replacing
1249
- * this function with mix() === mixImmediate
1250
- */
1251
- if (name === "display" || name === "visibility")
1252
- return true;
1253
- const targetKeyframe = keyframes[keyframes.length - 1];
1254
- const isOriginAnimatable = isAnimatable(originKeyframe, name);
1255
- const isTargetAnimatable = isAnimatable(targetKeyframe, name);
1256
- motionUtils.warning(isOriginAnimatable === isTargetAnimatable, `You are trying to animate ${name} from "${originKeyframe}" to "${targetKeyframe}". ${originKeyframe} is not an animatable value - to enable this animation set ${originKeyframe} to a value animatable to ${targetKeyframe} via the \`style\` property.`);
1257
- // Always skip if any of these are true
1258
- if (!isOriginAnimatable || !isTargetAnimatable) {
1259
- return false;
1260
- }
1261
- return (hasKeyframesChanged(keyframes) ||
1262
- ((type === "spring" || motionDom.isGenerator(type)) && velocity));
1263
- }
1264
-
1265
- const isNotNull = (value) => value !== null;
1266
- function getFinalKeyframe(keyframes, { repeat, repeatType = "loop" }, finalKeyframe) {
1267
- const resolvedKeyframes = keyframes.filter(isNotNull);
1268
- const index = repeat && repeatType !== "loop" && repeat % 2 === 1
1269
- ? 0
1270
- : resolvedKeyframes.length - 1;
1271
- return !index || finalKeyframe === undefined
1272
- ? resolvedKeyframes[index]
1273
- : finalKeyframe;
1274
- }
1275
-
1276
- /**
1277
- * Maximum time allowed between an animation being created and it being
1278
- * resolved for us to use the latter as the start time.
1279
- *
1280
- * This is to ensure that while we prefer to "start" an animation as soon
1281
- * as it's triggered, we also want to avoid a visual jump if there's a big delay
1282
- * between these two moments.
1283
- */
1284
- const MAX_RESOLVE_DELAY = 40;
1285
- class BaseAnimation {
1286
- constructor({ autoplay = true, delay = 0, type = "keyframes", repeat = 0, repeatDelay = 0, repeatType = "loop", ...options }) {
1287
- // Track whether the animation has been stopped. Stopped animations won't restart.
1288
- this.isStopped = false;
1289
- this.hasAttemptedResolve = false;
1290
- this.createdAt = motionDom.time.now();
1291
- this.options = {
1292
- autoplay,
1293
- delay,
1294
- type,
1295
- repeat,
1296
- repeatDelay,
1297
- repeatType,
1298
- ...options,
1299
- };
1300
- this.updateFinishedPromise();
1301
- }
1302
- /**
1303
- * This method uses the createdAt and resolvedAt to calculate the
1304
- * animation startTime. *Ideally*, we would use the createdAt time as t=0
1305
- * as the following frame would then be the first frame of the animation in
1306
- * progress, which would feel snappier.
1307
- *
1308
- * However, if there's a delay (main thread work) between the creation of
1309
- * the animation and the first commited frame, we prefer to use resolvedAt
1310
- * to avoid a sudden jump into the animation.
1311
- */
1312
- calcStartTime() {
1313
- if (!this.resolvedAt)
1314
- return this.createdAt;
1315
- return this.resolvedAt - this.createdAt > MAX_RESOLVE_DELAY
1316
- ? this.resolvedAt
1317
- : this.createdAt;
1318
- }
1319
- /**
1320
- * A getter for resolved data. If keyframes are not yet resolved, accessing
1321
- * this.resolved will synchronously flush all pending keyframe resolvers.
1322
- * This is a deoptimisation, but at its worst still batches read/writes.
1323
- */
1324
- get resolved() {
1325
- if (!this._resolved && !this.hasAttemptedResolve) {
1326
- flushKeyframeResolvers();
1327
- }
1328
- return this._resolved;
1329
- }
1330
- /**
1331
- * A method to be called when the keyframes resolver completes. This method
1332
- * will check if its possible to run the animation and, if not, skip it.
1333
- * Otherwise, it will call initPlayback on the implementing class.
1334
- */
1335
- onKeyframesResolved(keyframes, finalKeyframe) {
1336
- this.resolvedAt = motionDom.time.now();
1337
- this.hasAttemptedResolve = true;
1338
- const { name, type, velocity, delay, onComplete, onUpdate, isGenerator, } = this.options;
1339
- /**
1340
- * If we can't animate this value with the resolved keyframes
1341
- * then we should complete it immediately.
1342
- */
1343
- if (!isGenerator && !canAnimate(keyframes, name, type, velocity)) {
1344
- // Finish immediately
1345
- if (instantAnimationState.current || !delay) {
1346
- onUpdate &&
1347
- onUpdate(getFinalKeyframe(keyframes, this.options, finalKeyframe));
1348
- onComplete && onComplete();
1349
- this.resolveFinishedPromise();
1350
- return;
1351
- }
1352
- // Finish after a delay
1353
- else {
1354
- this.options.duration = 0;
1355
- }
1356
- }
1357
- const resolvedAnimation = this.initPlayback(keyframes, finalKeyframe);
1358
- if (resolvedAnimation === false)
1359
- return;
1360
- this._resolved = {
1361
- keyframes,
1362
- finalKeyframe,
1363
- ...resolvedAnimation,
1364
- };
1365
- this.onPostResolved();
1366
- }
1367
- onPostResolved() { }
1368
- /**
1369
- * Allows the returned animation to be awaited or promise-chained. Currently
1370
- * resolves when the animation finishes at all but in a future update could/should
1371
- * reject if its cancels.
1372
- */
1373
- then(resolve, reject) {
1374
- return this.currentFinishedPromise.then(resolve, reject);
1375
- }
1376
- flatten() {
1377
- if (!this.options.allowFlatten)
1378
- return;
1379
- this.options.type = "keyframes";
1380
- this.options.ease = "linear";
1381
- }
1382
- updateFinishedPromise() {
1383
- this.currentFinishedPromise = new Promise((resolve) => {
1384
- this.resolveFinishedPromise = resolve;
1385
- });
1386
- }
1387
- }
1388
-
1389
- // Adapted from https://gist.github.com/mjackson/5311256
1390
- function hueToRgb(p, q, t) {
1391
- if (t < 0)
1392
- t += 1;
1393
- if (t > 1)
1394
- t -= 1;
1395
- if (t < 1 / 6)
1396
- return p + (q - p) * 6 * t;
1397
- if (t < 1 / 2)
1398
- return q;
1399
- if (t < 2 / 3)
1400
- return p + (q - p) * (2 / 3 - t) * 6;
1401
- return p;
1402
- }
1403
- function hslaToRgba({ hue, saturation, lightness, alpha }) {
1404
- hue /= 360;
1405
- saturation /= 100;
1406
- lightness /= 100;
1407
- let red = 0;
1408
- let green = 0;
1409
- let blue = 0;
1410
- if (!saturation) {
1411
- red = green = blue = lightness;
1412
- }
1413
- else {
1414
- const q = lightness < 0.5
1415
- ? lightness * (1 + saturation)
1416
- : lightness + saturation - lightness * saturation;
1417
- const p = 2 * lightness - q;
1418
- red = hueToRgb(p, q, hue + 1 / 3);
1419
- green = hueToRgb(p, q, hue);
1420
- blue = hueToRgb(p, q, hue - 1 / 3);
1421
- }
1422
- return {
1423
- red: Math.round(red * 255),
1424
- green: Math.round(green * 255),
1425
- blue: Math.round(blue * 255),
1426
- alpha,
1427
- };
1428
- }
1429
-
1430
- function mixImmediate(a, b) {
1431
- return (p) => (p > 0 ? b : a);
1432
- }
1433
-
1434
- // Linear color space blending
1435
- // Explained https://www.youtube.com/watch?v=LKnqECcg6Gw
1436
- // Demonstrated http://codepen.io/osublake/pen/xGVVaN
1437
- const mixLinearColor = (from, to, v) => {
1438
- const fromExpo = from * from;
1439
- const expo = v * (to * to - fromExpo) + fromExpo;
1440
- return expo < 0 ? 0 : Math.sqrt(expo);
1441
- };
1442
- const colorTypes = [hex, rgba, hsla];
1443
- const getColorType = (v) => colorTypes.find((type) => type.test(v));
1444
- function asRGBA(color) {
1445
- const type = getColorType(color);
1446
- motionUtils.warning(Boolean(type), `'${color}' is not an animatable color. Use the equivalent color code instead.`);
1447
- if (!Boolean(type))
1448
- return false;
1449
- let model = type.parse(color);
1450
- if (type === hsla) {
1451
- // TODO Remove this cast - needed since Motion's stricter typing
1452
- model = hslaToRgba(model);
1453
- }
1454
- return model;
1455
- }
1456
- const mixColor = (from, to) => {
1457
- const fromRGBA = asRGBA(from);
1458
- const toRGBA = asRGBA(to);
1459
- if (!fromRGBA || !toRGBA) {
1460
- return mixImmediate(from, to);
1461
- }
1462
- const blended = { ...fromRGBA };
1463
- return (v) => {
1464
- blended.red = mixLinearColor(fromRGBA.red, toRGBA.red, v);
1465
- blended.green = mixLinearColor(fromRGBA.green, toRGBA.green, v);
1466
- blended.blue = mixLinearColor(fromRGBA.blue, toRGBA.blue, v);
1467
- blended.alpha = mixNumber$1(fromRGBA.alpha, toRGBA.alpha, v);
1468
- return rgba.transform(blended);
1469
- };
1470
- };
1471
-
1472
- /**
1473
- * Pipe
1474
- * Compose other transformers to run linearily
1475
- * pipe(min(20), max(40))
1476
- * @param {...functions} transformers
1477
- * @return {function}
1478
- */
1479
- const combineFunctions = (a, b) => (v) => b(a(v));
1480
- const pipe = (...transformers) => transformers.reduce(combineFunctions);
1481
-
1482
- const invisibleValues = new Set(["none", "hidden"]);
1483
- /**
1484
- * Returns a function that, when provided a progress value between 0 and 1,
1485
- * will return the "none" or "hidden" string only when the progress is that of
1486
- * the origin or target.
1487
- */
1488
- function mixVisibility(origin, target) {
1489
- if (invisibleValues.has(origin)) {
1490
- return (p) => (p <= 0 ? origin : target);
1491
- }
1492
- else {
1493
- return (p) => (p >= 1 ? target : origin);
1494
- }
1495
- }
1496
-
1497
- function mixNumber(a, b) {
1498
- return (p) => mixNumber$1(a, b, p);
1499
- }
1500
- function getMixer(a) {
1501
- if (typeof a === "number") {
1502
- return mixNumber;
1503
- }
1504
- else if (typeof a === "string") {
1505
- return isCSSVariableToken(a)
1506
- ? mixImmediate
1507
- : color.test(a)
1508
- ? mixColor
1509
- : mixComplex;
1510
- }
1511
- else if (Array.isArray(a)) {
1512
- return mixArray;
1513
- }
1514
- else if (typeof a === "object") {
1515
- return color.test(a) ? mixColor : mixObject;
1516
- }
1517
- return mixImmediate;
1518
- }
1519
- function mixArray(a, b) {
1520
- const output = [...a];
1521
- const numValues = output.length;
1522
- const blendValue = a.map((v, i) => getMixer(v)(v, b[i]));
1523
- return (p) => {
1524
- for (let i = 0; i < numValues; i++) {
1525
- output[i] = blendValue[i](p);
1526
- }
1527
- return output;
1528
- };
1529
- }
1530
- function mixObject(a, b) {
1531
- const output = { ...a, ...b };
1532
- const blendValue = {};
1533
- for (const key in output) {
1534
- if (a[key] !== undefined && b[key] !== undefined) {
1535
- blendValue[key] = getMixer(a[key])(a[key], b[key]);
1536
- }
1537
- }
1538
- return (v) => {
1539
- for (const key in blendValue) {
1540
- output[key] = blendValue[key](v);
1541
- }
1542
- return output;
1543
- };
1544
- }
1545
- function matchOrder(origin, target) {
1546
- const orderedOrigin = [];
1547
- const pointers = { color: 0, var: 0, number: 0 };
1548
- for (let i = 0; i < target.values.length; i++) {
1549
- const type = target.types[i];
1550
- const originIndex = origin.indexes[type][pointers[type]];
1551
- const originValue = origin.values[originIndex] ?? 0;
1552
- orderedOrigin[i] = originValue;
1553
- pointers[type]++;
1554
- }
1555
- return orderedOrigin;
1556
- }
1557
- const mixComplex = (origin, target) => {
1558
- const template = complex.createTransformer(target);
1559
- const originStats = analyseComplexValue(origin);
1560
- const targetStats = analyseComplexValue(target);
1561
- const canInterpolate = originStats.indexes.var.length === targetStats.indexes.var.length &&
1562
- originStats.indexes.color.length === targetStats.indexes.color.length &&
1563
- originStats.indexes.number.length >= targetStats.indexes.number.length;
1564
- if (canInterpolate) {
1565
- if ((invisibleValues.has(origin) &&
1566
- !targetStats.values.length) ||
1567
- (invisibleValues.has(target) &&
1568
- !originStats.values.length)) {
1569
- return mixVisibility(origin, target);
1570
- }
1571
- return pipe(mixArray(matchOrder(originStats, targetStats), targetStats.values), template);
1572
- }
1573
- else {
1574
- motionUtils.warning(true, `Complex values '${origin}' and '${target}' too different to mix. Ensure all colors are of the same type, and that each contains the same quantity of number and color values. Falling back to instant transition.`);
1575
- return mixImmediate(origin, target);
1576
- }
1577
- };
1578
-
1579
- function mix(from, to, p) {
1580
- if (typeof from === "number" &&
1581
- typeof to === "number" &&
1582
- typeof p === "number") {
1583
- return mixNumber$1(from, to, p);
1584
- }
1585
- const mixer = getMixer(from);
1586
- return mixer(from, to);
1587
- }
1588
-
1589
- const velocitySampleDuration = 5; // ms
1590
- function calcGeneratorVelocity(resolveValue, t, current) {
1591
- const prevT = Math.max(t - velocitySampleDuration, 0);
1592
- return motionUtils.velocityPerSecond(current - resolveValue(prevT), t - prevT);
1593
- }
1594
-
1595
- const springDefaults = {
1596
- // Default spring physics
1597
- stiffness: 100,
1598
- damping: 10,
1599
- mass: 1.0,
1600
- velocity: 0.0,
1601
- // Default duration/bounce-based options
1602
- duration: 800, // in ms
1603
- bounce: 0.3,
1604
- visualDuration: 0.3, // in seconds
1605
- // Rest thresholds
1606
- restSpeed: {
1607
- granular: 0.01,
1608
- default: 2,
1609
- },
1610
- restDelta: {
1611
- granular: 0.005,
1612
- default: 0.5,
1613
- },
1614
- // Limits
1615
- minDuration: 0.01, // in seconds
1616
- maxDuration: 10.0, // in seconds
1617
- minDamping: 0.05,
1618
- maxDamping: 1,
1619
- };
1620
-
1621
- const safeMin = 0.001;
1622
- function findSpring({ duration = springDefaults.duration, bounce = springDefaults.bounce, velocity = springDefaults.velocity, mass = springDefaults.mass, }) {
1623
- let envelope;
1624
- let derivative;
1625
- motionUtils.warning(duration <= motionUtils.secondsToMilliseconds(springDefaults.maxDuration), "Spring duration must be 10 seconds or less");
1626
- let dampingRatio = 1 - bounce;
1627
- /**
1628
- * Restrict dampingRatio and duration to within acceptable ranges.
1629
- */
1630
- dampingRatio = clamp(springDefaults.minDamping, springDefaults.maxDamping, dampingRatio);
1631
- duration = clamp(springDefaults.minDuration, springDefaults.maxDuration, motionUtils.millisecondsToSeconds(duration));
1632
- if (dampingRatio < 1) {
1633
- /**
1634
- * Underdamped spring
1635
- */
1636
- envelope = (undampedFreq) => {
1637
- const exponentialDecay = undampedFreq * dampingRatio;
1638
- const delta = exponentialDecay * duration;
1639
- const a = exponentialDecay - velocity;
1640
- const b = calcAngularFreq(undampedFreq, dampingRatio);
1641
- const c = Math.exp(-delta);
1642
- return safeMin - (a / b) * c;
1643
- };
1644
- derivative = (undampedFreq) => {
1645
- const exponentialDecay = undampedFreq * dampingRatio;
1646
- const delta = exponentialDecay * duration;
1647
- const d = delta * velocity + velocity;
1648
- const e = Math.pow(dampingRatio, 2) * Math.pow(undampedFreq, 2) * duration;
1649
- const f = Math.exp(-delta);
1650
- const g = calcAngularFreq(Math.pow(undampedFreq, 2), dampingRatio);
1651
- const factor = -envelope(undampedFreq) + safeMin > 0 ? -1 : 1;
1652
- return (factor * ((d - e) * f)) / g;
1653
- };
1654
- }
1655
- else {
1656
- /**
1657
- * Critically-damped spring
1658
- */
1659
- envelope = (undampedFreq) => {
1660
- const a = Math.exp(-undampedFreq * duration);
1661
- const b = (undampedFreq - velocity) * duration + 1;
1662
- return -safeMin + a * b;
1663
- };
1664
- derivative = (undampedFreq) => {
1665
- const a = Math.exp(-undampedFreq * duration);
1666
- const b = (velocity - undampedFreq) * (duration * duration);
1667
- return a * b;
1668
- };
1669
- }
1670
- const initialGuess = 5 / duration;
1671
- const undampedFreq = approximateRoot(envelope, derivative, initialGuess);
1672
- duration = motionUtils.secondsToMilliseconds(duration);
1673
- if (isNaN(undampedFreq)) {
1674
- return {
1675
- stiffness: springDefaults.stiffness,
1676
- damping: springDefaults.damping,
1677
- duration,
1678
- };
1679
- }
1680
- else {
1681
- const stiffness = Math.pow(undampedFreq, 2) * mass;
1682
- return {
1683
- stiffness,
1684
- damping: dampingRatio * 2 * Math.sqrt(mass * stiffness),
1685
- duration,
1686
- };
1687
- }
1688
- }
1689
- const rootIterations = 12;
1690
- function approximateRoot(envelope, derivative, initialGuess) {
1691
- let result = initialGuess;
1692
- for (let i = 1; i < rootIterations; i++) {
1693
- result = result - envelope(result) / derivative(result);
1694
- }
1695
- return result;
1696
- }
1697
- function calcAngularFreq(undampedFreq, dampingRatio) {
1698
- return undampedFreq * Math.sqrt(1 - dampingRatio * dampingRatio);
1699
- }
1700
-
1701
- const durationKeys = ["duration", "bounce"];
1702
- const physicsKeys = ["stiffness", "damping", "mass"];
1703
- function isSpringType(options, keys) {
1704
- return keys.some((key) => options[key] !== undefined);
1705
- }
1706
- function getSpringOptions(options) {
1707
- let springOptions = {
1708
- velocity: springDefaults.velocity,
1709
- stiffness: springDefaults.stiffness,
1710
- damping: springDefaults.damping,
1711
- mass: springDefaults.mass,
1712
- isResolvedFromDuration: false,
1713
- ...options,
1714
- };
1715
- // stiffness/damping/mass overrides duration/bounce
1716
- if (!isSpringType(options, physicsKeys) &&
1717
- isSpringType(options, durationKeys)) {
1718
- if (options.visualDuration) {
1719
- const visualDuration = options.visualDuration;
1720
- const root = (2 * Math.PI) / (visualDuration * 1.2);
1721
- const stiffness = root * root;
1722
- const damping = 2 *
1723
- clamp(0.05, 1, 1 - (options.bounce || 0)) *
1724
- Math.sqrt(stiffness);
1725
- springOptions = {
1726
- ...springOptions,
1727
- mass: springDefaults.mass,
1728
- stiffness,
1729
- damping,
1730
- };
1731
- }
1732
- else {
1733
- const derived = findSpring(options);
1734
- springOptions = {
1735
- ...springOptions,
1736
- ...derived,
1737
- mass: springDefaults.mass,
1738
- };
1739
- springOptions.isResolvedFromDuration = true;
1740
- }
1741
- }
1742
- return springOptions;
1743
- }
1744
- function spring(optionsOrVisualDuration = springDefaults.visualDuration, bounce = springDefaults.bounce) {
1745
- const options = typeof optionsOrVisualDuration !== "object"
1746
- ? {
1747
- visualDuration: optionsOrVisualDuration,
1748
- keyframes: [0, 1],
1749
- bounce,
1750
- }
1751
- : optionsOrVisualDuration;
1752
- let { restSpeed, restDelta } = options;
1753
- const origin = options.keyframes[0];
1754
- const target = options.keyframes[options.keyframes.length - 1];
1755
- /**
1756
- * This is the Iterator-spec return value. We ensure it's mutable rather than using a generator
1757
- * to reduce GC during animation.
1758
- */
1759
- const state = { done: false, value: origin };
1760
- const { stiffness, damping, mass, duration, velocity, isResolvedFromDuration, } = getSpringOptions({
1761
- ...options,
1762
- velocity: -motionUtils.millisecondsToSeconds(options.velocity || 0),
1763
- });
1764
- const initialVelocity = velocity || 0.0;
1765
- const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass));
1766
- const initialDelta = target - origin;
1767
- const undampedAngularFreq = motionUtils.millisecondsToSeconds(Math.sqrt(stiffness / mass));
1768
- /**
1769
- * If we're working on a granular scale, use smaller defaults for determining
1770
- * when the spring is finished.
1771
- *
1772
- * These defaults have been selected emprically based on what strikes a good
1773
- * ratio between feeling good and finishing as soon as changes are imperceptible.
1774
- */
1775
- const isGranularScale = Math.abs(initialDelta) < 5;
1776
- restSpeed || (restSpeed = isGranularScale
1777
- ? springDefaults.restSpeed.granular
1778
- : springDefaults.restSpeed.default);
1779
- restDelta || (restDelta = isGranularScale
1780
- ? springDefaults.restDelta.granular
1781
- : springDefaults.restDelta.default);
1782
- let resolveSpring;
1783
- if (dampingRatio < 1) {
1784
- const angularFreq = calcAngularFreq(undampedAngularFreq, dampingRatio);
1785
- // Underdamped spring
1786
- resolveSpring = (t) => {
1787
- const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
1788
- return (target -
1789
- envelope *
1790
- (((initialVelocity +
1791
- dampingRatio * undampedAngularFreq * initialDelta) /
1792
- angularFreq) *
1793
- Math.sin(angularFreq * t) +
1794
- initialDelta * Math.cos(angularFreq * t)));
1795
- };
1796
- }
1797
- else if (dampingRatio === 1) {
1798
- // Critically damped spring
1799
- resolveSpring = (t) => target -
1800
- Math.exp(-undampedAngularFreq * t) *
1801
- (initialDelta +
1802
- (initialVelocity + undampedAngularFreq * initialDelta) * t);
1803
- }
1804
- else {
1805
- // Overdamped spring
1806
- const dampedAngularFreq = undampedAngularFreq * Math.sqrt(dampingRatio * dampingRatio - 1);
1807
- resolveSpring = (t) => {
1808
- const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
1809
- // When performing sinh or cosh values can hit Infinity so we cap them here
1810
- const freqForT = Math.min(dampedAngularFreq * t, 300);
1811
- return (target -
1812
- (envelope *
1813
- ((initialVelocity +
1814
- dampingRatio * undampedAngularFreq * initialDelta) *
1815
- Math.sinh(freqForT) +
1816
- dampedAngularFreq *
1817
- initialDelta *
1818
- Math.cosh(freqForT))) /
1819
- dampedAngularFreq);
1820
- };
1821
- }
1822
- const generator = {
1823
- calculatedDuration: isResolvedFromDuration ? duration || null : null,
1824
- next: (t) => {
1825
- const current = resolveSpring(t);
1826
- if (!isResolvedFromDuration) {
1827
- let currentVelocity = 0.0;
1828
- /**
1829
- * We only need to calculate velocity for under-damped springs
1830
- * as over- and critically-damped springs can't overshoot, so
1831
- * checking only for displacement is enough.
1832
- */
1833
- if (dampingRatio < 1) {
1834
- currentVelocity =
1835
- t === 0
1836
- ? motionUtils.secondsToMilliseconds(initialVelocity)
1837
- : calcGeneratorVelocity(resolveSpring, t, current);
1838
- }
1839
- const isBelowVelocityThreshold = Math.abs(currentVelocity) <= restSpeed;
1840
- const isBelowDisplacementThreshold = Math.abs(target - current) <= restDelta;
1841
- state.done =
1842
- isBelowVelocityThreshold && isBelowDisplacementThreshold;
1843
- }
1844
- else {
1845
- state.done = t >= duration;
1846
- }
1847
- state.value = state.done ? target : current;
1848
- return state;
1849
- },
1850
- toString: () => {
1851
- const calculatedDuration = Math.min(motionDom.calcGeneratorDuration(generator), motionDom.maxGeneratorDuration);
1852
- const easing = motionDom.generateLinearEasing((progress) => generator.next(calculatedDuration * progress).value, calculatedDuration, 30);
1853
- return calculatedDuration + "ms " + easing;
1854
- },
1855
- toTransition: () => { },
1856
- };
1857
- return generator;
1858
- }
1859
- spring.applyToOptions = (options) => {
1860
- const generatorOptions = motionDom.createGeneratorEasing(options, 100, spring);
1861
- options.ease = motionDom.supportsLinearEasing() ? generatorOptions.ease : "easeOut";
1862
- options.duration = motionUtils.secondsToMilliseconds(generatorOptions.duration);
1863
- options.type = "keyframes";
1864
- return options;
1865
- };
1866
-
1867
- function inertia({ keyframes, velocity = 0.0, power = 0.8, timeConstant = 325, bounceDamping = 10, bounceStiffness = 500, modifyTarget, min, max, restDelta = 0.5, restSpeed, }) {
1868
- const origin = keyframes[0];
1869
- const state = {
1870
- done: false,
1871
- value: origin,
1872
- };
1873
- const isOutOfBounds = (v) => (min !== undefined && v < min) || (max !== undefined && v > max);
1874
- const nearestBoundary = (v) => {
1875
- if (min === undefined)
1876
- return max;
1877
- if (max === undefined)
1878
- return min;
1879
- return Math.abs(min - v) < Math.abs(max - v) ? min : max;
1880
- };
1881
- let amplitude = power * velocity;
1882
- const ideal = origin + amplitude;
1883
- const target = modifyTarget === undefined ? ideal : modifyTarget(ideal);
1884
- /**
1885
- * If the target has changed we need to re-calculate the amplitude, otherwise
1886
- * the animation will start from the wrong position.
1887
- */
1888
- if (target !== ideal)
1889
- amplitude = target - origin;
1890
- const calcDelta = (t) => -amplitude * Math.exp(-t / timeConstant);
1891
- const calcLatest = (t) => target + calcDelta(t);
1892
- const applyFriction = (t) => {
1893
- const delta = calcDelta(t);
1894
- const latest = calcLatest(t);
1895
- state.done = Math.abs(delta) <= restDelta;
1896
- state.value = state.done ? target : latest;
1897
- };
1898
- /**
1899
- * Ideally this would resolve for t in a stateless way, we could
1900
- * do that by always precalculating the animation but as we know
1901
- * this will be done anyway we can assume that spring will
1902
- * be discovered during that.
1903
- */
1904
- let timeReachedBoundary;
1905
- let spring$1;
1906
- const checkCatchBoundary = (t) => {
1907
- if (!isOutOfBounds(state.value))
1908
- return;
1909
- timeReachedBoundary = t;
1910
- spring$1 = spring({
1911
- keyframes: [state.value, nearestBoundary(state.value)],
1912
- velocity: calcGeneratorVelocity(calcLatest, t, state.value), // TODO: This should be passing * 1000
1913
- damping: bounceDamping,
1914
- stiffness: bounceStiffness,
1915
- restDelta,
1916
- restSpeed,
1917
- });
1918
- };
1919
- checkCatchBoundary(0);
1920
- return {
1921
- calculatedDuration: null,
1922
- next: (t) => {
1923
- /**
1924
- * We need to resolve the friction to figure out if we need a
1925
- * spring but we don't want to do this twice per frame. So here
1926
- * we flag if we updated for this frame and later if we did
1927
- * we can skip doing it again.
1928
- */
1929
- let hasUpdatedFrame = false;
1930
- if (!spring$1 && timeReachedBoundary === undefined) {
1931
- hasUpdatedFrame = true;
1932
- applyFriction(t);
1933
- checkCatchBoundary(t);
1934
- }
1935
- /**
1936
- * If we have a spring and the provided t is beyond the moment the friction
1937
- * animation crossed the min/max boundary, use the spring.
1938
- */
1939
- if (timeReachedBoundary !== undefined && t >= timeReachedBoundary) {
1940
- return spring$1.next(t - timeReachedBoundary);
1941
- }
1942
- else {
1943
- !hasUpdatedFrame && applyFriction(t);
1944
- return state;
1945
- }
1946
- },
1947
- };
1948
- }
1949
-
1950
- const easeIn = /*@__PURE__*/ cubicBezier(0.42, 0, 1, 1);
1951
- const easeOut = /*@__PURE__*/ cubicBezier(0, 0, 0.58, 1);
1952
- const easeInOut = /*@__PURE__*/ cubicBezier(0.42, 0, 0.58, 1);
1953
-
1954
- const isEasingArray = (ease) => {
1955
- return Array.isArray(ease) && typeof ease[0] !== "number";
1956
- };
1957
-
1958
- const easingLookup = {
1959
- linear: motionUtils.noop,
1960
- easeIn,
1961
- easeInOut,
1962
- easeOut,
1963
- circIn,
1964
- circInOut,
1965
- circOut,
1966
- backIn,
1967
- backInOut,
1968
- backOut,
1969
- anticipate,
1970
- };
1971
- const easingDefinitionToFunction = (definition) => {
1972
- if (motionDom.isBezierDefinition(definition)) {
1973
- // If cubic bezier definition, create bezier curve
1974
- motionUtils.invariant(definition.length === 4, `Cubic bezier arrays must contain four numerical values.`);
1975
- const [x1, y1, x2, y2] = definition;
1976
- return cubicBezier(x1, y1, x2, y2);
1977
- }
1978
- else if (typeof definition === "string") {
1979
- // Else lookup from table
1980
- motionUtils.invariant(easingLookup[definition] !== undefined, `Invalid easing type '${definition}'`);
1981
- return easingLookup[definition];
1982
- }
1983
- return definition;
1984
- };
1985
-
1986
- function createMixers(output, ease, customMixer) {
1987
- const mixers = [];
1988
- const mixerFactory = customMixer || mix;
1989
- const numMixers = output.length - 1;
1990
- for (let i = 0; i < numMixers; i++) {
1991
- let mixer = mixerFactory(output[i], output[i + 1]);
1992
- if (ease) {
1993
- const easingFunction = Array.isArray(ease) ? ease[i] || motionUtils.noop : ease;
1994
- mixer = pipe(easingFunction, mixer);
1995
- }
1996
- mixers.push(mixer);
1997
- }
1998
- return mixers;
1999
- }
2000
- /**
2001
- * Create a function that maps from a numerical input array to a generic output array.
2002
- *
2003
- * Accepts:
2004
- * - Numbers
2005
- * - Colors (hex, hsl, hsla, rgb, rgba)
2006
- * - Complex (combinations of one or more numbers or strings)
2007
- *
2008
- * ```jsx
2009
- * const mixColor = interpolate([0, 1], ['#fff', '#000'])
2010
- *
2011
- * mixColor(0.5) // 'rgba(128, 128, 128, 1)'
2012
- * ```
2013
- *
2014
- * TODO Revist this approach once we've moved to data models for values,
2015
- * probably not needed to pregenerate mixer functions.
2016
- *
2017
- * @public
2018
- */
2019
- function interpolate(input, output, { clamp: isClamp = true, ease, mixer } = {}) {
2020
- const inputLength = input.length;
2021
- motionUtils.invariant(inputLength === output.length, "Both input and output ranges must be the same length");
2022
- /**
2023
- * If we're only provided a single input, we can just make a function
2024
- * that returns the output.
2025
- */
2026
- if (inputLength === 1)
2027
- return () => output[0];
2028
- if (inputLength === 2 && output[0] === output[1])
2029
- return () => output[1];
2030
- const isZeroDeltaRange = input[0] === input[1];
2031
- // If input runs highest -> lowest, reverse both arrays
2032
- if (input[0] > input[inputLength - 1]) {
2033
- input = [...input].reverse();
2034
- output = [...output].reverse();
2035
- }
2036
- const mixers = createMixers(output, ease, mixer);
2037
- const numMixers = mixers.length;
2038
- const interpolator = (v) => {
2039
- if (isZeroDeltaRange && v < input[0])
2040
- return output[0];
2041
- let i = 0;
2042
- if (numMixers > 1) {
2043
- for (; i < input.length - 2; i++) {
2044
- if (v < input[i + 1])
2045
- break;
2046
- }
2047
- }
2048
- const progressInRange = motionUtils.progress(input[i], input[i + 1], v);
2049
- return mixers[i](progressInRange);
2050
- };
2051
- return isClamp
2052
- ? (v) => interpolator(clamp(input[0], input[inputLength - 1], v))
2053
- : interpolator;
2054
- }
2055
-
2056
- function fillOffset(offset, remaining) {
2057
- const min = offset[offset.length - 1];
2058
- for (let i = 1; i <= remaining; i++) {
2059
- const offsetProgress = motionUtils.progress(0, remaining, i);
2060
- offset.push(mixNumber$1(min, 1, offsetProgress));
2061
- }
2062
- }
2063
-
2064
- function defaultOffset(arr) {
2065
- const offset = [0];
2066
- fillOffset(offset, arr.length - 1);
2067
- return offset;
136
+ }
2068
137
  }
2069
-
2070
- function convertOffsetToTimes(offset, duration) {
2071
- return offset.map((o) => o * duration);
138
+ function calcBoxDelta(delta, source, target, origin) {
139
+ calcAxisDelta(delta.x, source.x, target.x, origin ? origin.originX : undefined);
140
+ calcAxisDelta(delta.y, source.y, target.y, origin ? origin.originY : undefined);
2072
141
  }
2073
-
2074
- function defaultEasing(values, easing) {
2075
- return values.map(() => easing || easeInOut).splice(0, values.length - 1);
142
+ function calcRelativeAxis(target, relative, parent) {
143
+ target.min = parent.min + relative.min;
144
+ target.max = target.min + calcLength(relative);
2076
145
  }
2077
- function keyframes({ duration = 300, keyframes: keyframeValues, times, ease = "easeInOut", }) {
2078
- /**
2079
- * Easing functions can be externally defined as strings. Here we convert them
2080
- * into actual functions.
2081
- */
2082
- const easingFunctions = isEasingArray(ease)
2083
- ? ease.map(easingDefinitionToFunction)
2084
- : easingDefinitionToFunction(ease);
2085
- /**
2086
- * This is the Iterator-spec return value. We ensure it's mutable rather than using a generator
2087
- * to reduce GC during animation.
2088
- */
2089
- const state = {
2090
- done: false,
2091
- value: keyframeValues[0],
2092
- };
2093
- /**
2094
- * Create a times array based on the provided 0-1 offsets
2095
- */
2096
- const absoluteTimes = convertOffsetToTimes(
2097
- // Only use the provided offsets if they're the correct length
2098
- // TODO Maybe we should warn here if there's a length mismatch
2099
- times && times.length === keyframeValues.length
2100
- ? times
2101
- : defaultOffset(keyframeValues), duration);
2102
- const mapTimeToKeyframe = interpolate(absoluteTimes, keyframeValues, {
2103
- ease: Array.isArray(easingFunctions)
2104
- ? easingFunctions
2105
- : defaultEasing(keyframeValues, easingFunctions),
2106
- });
2107
- return {
2108
- calculatedDuration: duration,
2109
- next: (t) => {
2110
- state.value = mapTimeToKeyframe(t);
2111
- state.done = t >= duration;
2112
- return state;
2113
- },
2114
- };
146
+ function calcRelativeBox(target, relative, parent) {
147
+ calcRelativeAxis(target.x, relative.x, parent.x);
148
+ calcRelativeAxis(target.y, relative.y, parent.y);
2115
149
  }
2116
-
2117
- const frameloopDriver = (update) => {
2118
- const passTimestamp = ({ timestamp }) => update(timestamp);
2119
- return {
2120
- start: () => motionDom.frame.update(passTimestamp, true),
2121
- stop: () => motionDom.cancelFrame(passTimestamp),
2122
- /**
2123
- * If we're processing this frame we can use the
2124
- * framelocked timestamp to keep things in sync.
2125
- */
2126
- now: () => (motionDom.frameData.isProcessing ? motionDom.frameData.timestamp : motionDom.time.now()),
2127
- };
2128
- };
2129
-
2130
- const generators = {
2131
- decay: inertia,
2132
- inertia,
2133
- tween: keyframes,
2134
- keyframes: keyframes,
2135
- spring,
2136
- };
2137
- const percentToProgress = (percent) => percent / 100;
2138
- /**
2139
- * Animation that runs on the main thread. Designed to be WAAPI-spec in the subset of
2140
- * features we expose publically. Mostly the compatibility is to ensure visual identity
2141
- * between both WAAPI and main thread animations.
2142
- */
2143
- class MainThreadAnimation extends BaseAnimation {
2144
- constructor(options) {
2145
- super(options);
2146
- /**
2147
- * The time at which the animation was paused.
2148
- */
2149
- this.holdTime = null;
2150
- /**
2151
- * The time at which the animation was cancelled.
2152
- */
2153
- this.cancelTime = null;
2154
- /**
2155
- * The current time of the animation.
2156
- */
2157
- this.currentTime = 0;
2158
- /**
2159
- * Playback speed as a factor. 0 would be stopped, -1 reverse and 2 double speed.
2160
- */
2161
- this.playbackSpeed = 1;
2162
- /**
2163
- * The state of the animation to apply when the animation is resolved. This
2164
- * allows calls to the public API to control the animation before it is resolved,
2165
- * without us having to resolve it first.
2166
- */
2167
- this.pendingPlayState = "running";
2168
- /**
2169
- * The time at which the animation was started.
2170
- */
2171
- this.startTime = null;
2172
- this.state = "idle";
2173
- /**
2174
- * This method is bound to the instance to fix a pattern where
2175
- * animation.stop is returned as a reference from a useEffect.
2176
- */
2177
- this.stop = () => {
2178
- this.resolver.cancel();
2179
- this.isStopped = true;
2180
- if (this.state === "idle")
2181
- return;
2182
- this.teardown();
2183
- const { onStop } = this.options;
2184
- onStop && onStop();
2185
- };
2186
- const { name, motionValue, element, keyframes } = this.options;
2187
- const KeyframeResolver$1 = element?.KeyframeResolver || KeyframeResolver;
2188
- const onResolved = (resolvedKeyframes, finalKeyframe) => this.onKeyframesResolved(resolvedKeyframes, finalKeyframe);
2189
- this.resolver = new KeyframeResolver$1(keyframes, onResolved, name, motionValue, element);
2190
- this.resolver.scheduleResolve();
2191
- }
2192
- flatten() {
2193
- super.flatten();
2194
- // If we've already resolved the animation, re-initialise it
2195
- if (this._resolved) {
2196
- Object.assign(this._resolved, this.initPlayback(this._resolved.keyframes));
2197
- }
2198
- }
2199
- initPlayback(keyframes$1) {
2200
- const { type = "keyframes", repeat = 0, repeatDelay = 0, repeatType, velocity = 0, } = this.options;
2201
- const generatorFactory = motionDom.isGenerator(type)
2202
- ? type
2203
- : generators[type] || keyframes;
2204
- /**
2205
- * If our generator doesn't support mixing numbers, we need to replace keyframes with
2206
- * [0, 100] and then make a function that maps that to the actual keyframes.
2207
- *
2208
- * 100 is chosen instead of 1 as it works nicer with spring animations.
2209
- */
2210
- let mapPercentToKeyframes;
2211
- let mirroredGenerator;
2212
- if (process.env.NODE_ENV !== "production" &&
2213
- generatorFactory !== keyframes) {
2214
- motionUtils.invariant(keyframes$1.length <= 2, `Only two keyframes currently supported with spring and inertia animations. Trying to animate ${keyframes$1}`);
2215
- }
2216
- if (generatorFactory !== keyframes &&
2217
- typeof keyframes$1[0] !== "number") {
2218
- mapPercentToKeyframes = pipe(percentToProgress, mix(keyframes$1[0], keyframes$1[1]));
2219
- keyframes$1 = [0, 100];
2220
- }
2221
- const generator = generatorFactory({ ...this.options, keyframes: keyframes$1 });
2222
- /**
2223
- * If we have a mirror repeat type we need to create a second generator that outputs the
2224
- * mirrored (not reversed) animation and later ping pong between the two generators.
2225
- */
2226
- if (repeatType === "mirror") {
2227
- mirroredGenerator = generatorFactory({
2228
- ...this.options,
2229
- keyframes: [...keyframes$1].reverse(),
2230
- velocity: -velocity,
2231
- });
2232
- }
2233
- /**
2234
- * If duration is undefined and we have repeat options,
2235
- * we need to calculate a duration from the generator.
2236
- *
2237
- * We set it to the generator itself to cache the duration.
2238
- * Any timeline resolver will need to have already precalculated
2239
- * the duration by this step.
2240
- */
2241
- if (generator.calculatedDuration === null) {
2242
- generator.calculatedDuration = motionDom.calcGeneratorDuration(generator);
2243
- }
2244
- const { calculatedDuration } = generator;
2245
- const resolvedDuration = calculatedDuration + repeatDelay;
2246
- const totalDuration = resolvedDuration * (repeat + 1) - repeatDelay;
2247
- return {
2248
- generator,
2249
- mirroredGenerator,
2250
- mapPercentToKeyframes,
2251
- calculatedDuration,
2252
- resolvedDuration,
2253
- totalDuration,
2254
- };
2255
- }
2256
- onPostResolved() {
2257
- const { autoplay = true } = this.options;
2258
- motionDom.activeAnimations.mainThread++;
2259
- this.play();
2260
- if (this.pendingPlayState === "paused" || !autoplay) {
2261
- this.pause();
2262
- }
2263
- else {
2264
- this.state = this.pendingPlayState;
2265
- }
2266
- }
2267
- tick(timestamp, sample = false) {
2268
- const { resolved } = this;
2269
- // If the animations has failed to resolve, return the final keyframe.
2270
- if (!resolved) {
2271
- const { keyframes } = this.options;
2272
- return { done: true, value: keyframes[keyframes.length - 1] };
2273
- }
2274
- const { finalKeyframe, generator, mirroredGenerator, mapPercentToKeyframes, keyframes, calculatedDuration, totalDuration, resolvedDuration, } = resolved;
2275
- if (this.startTime === null)
2276
- return generator.next(0);
2277
- const { delay, repeat, repeatType, repeatDelay, onUpdate } = this.options;
2278
- /**
2279
- * requestAnimationFrame timestamps can come through as lower than
2280
- * the startTime as set by performance.now(). Here we prevent this,
2281
- * though in the future it could be possible to make setting startTime
2282
- * a pending operation that gets resolved here.
2283
- */
2284
- if (this.speed > 0) {
2285
- this.startTime = Math.min(this.startTime, timestamp);
2286
- }
2287
- else if (this.speed < 0) {
2288
- this.startTime = Math.min(timestamp - totalDuration / this.speed, this.startTime);
2289
- }
2290
- // Update currentTime
2291
- if (sample) {
2292
- this.currentTime = timestamp;
2293
- }
2294
- else if (this.holdTime !== null) {
2295
- this.currentTime = this.holdTime;
2296
- }
2297
- else {
2298
- // Rounding the time because floating point arithmetic is not always accurate, e.g. 3000.367 - 1000.367 =
2299
- // 2000.0000000000002. This is a problem when we are comparing the currentTime with the duration, for
2300
- // example.
2301
- this.currentTime =
2302
- Math.round(timestamp - this.startTime) * this.speed;
2303
- }
2304
- // Rebase on delay
2305
- const timeWithoutDelay = this.currentTime - delay * (this.speed >= 0 ? 1 : -1);
2306
- const isInDelayPhase = this.speed >= 0
2307
- ? timeWithoutDelay < 0
2308
- : timeWithoutDelay > totalDuration;
2309
- this.currentTime = Math.max(timeWithoutDelay, 0);
2310
- // If this animation has finished, set the current time to the total duration.
2311
- if (this.state === "finished" && this.holdTime === null) {
2312
- this.currentTime = totalDuration;
2313
- }
2314
- let elapsed = this.currentTime;
2315
- let frameGenerator = generator;
2316
- if (repeat) {
2317
- /**
2318
- * Get the current progress (0-1) of the animation. If t is >
2319
- * than duration we'll get values like 2.5 (midway through the
2320
- * third iteration)
2321
- */
2322
- const progress = Math.min(this.currentTime, totalDuration) / resolvedDuration;
2323
- /**
2324
- * Get the current iteration (0 indexed). For instance the floor of
2325
- * 2.5 is 2.
2326
- */
2327
- let currentIteration = Math.floor(progress);
2328
- /**
2329
- * Get the current progress of the iteration by taking the remainder
2330
- * so 2.5 is 0.5 through iteration 2
2331
- */
2332
- let iterationProgress = progress % 1.0;
2333
- /**
2334
- * If iteration progress is 1 we count that as the end
2335
- * of the previous iteration.
2336
- */
2337
- if (!iterationProgress && progress >= 1) {
2338
- iterationProgress = 1;
2339
- }
2340
- iterationProgress === 1 && currentIteration--;
2341
- currentIteration = Math.min(currentIteration, repeat + 1);
2342
- /**
2343
- * Reverse progress if we're not running in "normal" direction
2344
- */
2345
- const isOddIteration = Boolean(currentIteration % 2);
2346
- if (isOddIteration) {
2347
- if (repeatType === "reverse") {
2348
- iterationProgress = 1 - iterationProgress;
2349
- if (repeatDelay) {
2350
- iterationProgress -= repeatDelay / resolvedDuration;
2351
- }
2352
- }
2353
- else if (repeatType === "mirror") {
2354
- frameGenerator = mirroredGenerator;
2355
- }
2356
- }
2357
- elapsed = clamp(0, 1, iterationProgress) * resolvedDuration;
2358
- }
2359
- /**
2360
- * If we're in negative time, set state as the initial keyframe.
2361
- * This prevents delay: x, duration: 0 animations from finishing
2362
- * instantly.
2363
- */
2364
- const state = isInDelayPhase
2365
- ? { done: false, value: keyframes[0] }
2366
- : frameGenerator.next(elapsed);
2367
- if (mapPercentToKeyframes) {
2368
- state.value = mapPercentToKeyframes(state.value);
2369
- }
2370
- let { done } = state;
2371
- if (!isInDelayPhase && calculatedDuration !== null) {
2372
- done =
2373
- this.speed >= 0
2374
- ? this.currentTime >= totalDuration
2375
- : this.currentTime <= 0;
2376
- }
2377
- const isAnimationFinished = this.holdTime === null &&
2378
- (this.state === "finished" || (this.state === "running" && done));
2379
- if (isAnimationFinished && finalKeyframe !== undefined) {
2380
- state.value = getFinalKeyframe(keyframes, this.options, finalKeyframe);
2381
- }
2382
- if (onUpdate) {
2383
- onUpdate(state.value);
2384
- }
2385
- if (isAnimationFinished) {
2386
- this.finish();
2387
- }
2388
- return state;
2389
- }
2390
- get duration() {
2391
- const { resolved } = this;
2392
- return resolved ? motionUtils.millisecondsToSeconds(resolved.calculatedDuration) : 0;
2393
- }
2394
- get time() {
2395
- return motionUtils.millisecondsToSeconds(this.currentTime);
2396
- }
2397
- set time(newTime) {
2398
- newTime = motionUtils.secondsToMilliseconds(newTime);
2399
- this.currentTime = newTime;
2400
- if (this.holdTime !== null || this.speed === 0) {
2401
- this.holdTime = newTime;
2402
- }
2403
- else if (this.driver) {
2404
- this.startTime = this.driver.now() - newTime / this.speed;
2405
- }
2406
- }
2407
- get speed() {
2408
- return this.playbackSpeed;
2409
- }
2410
- set speed(newSpeed) {
2411
- const hasChanged = this.playbackSpeed !== newSpeed;
2412
- this.playbackSpeed = newSpeed;
2413
- if (hasChanged) {
2414
- this.time = motionUtils.millisecondsToSeconds(this.currentTime);
2415
- }
2416
- }
2417
- play() {
2418
- if (!this.resolver.isScheduled) {
2419
- this.resolver.resume();
2420
- }
2421
- if (!this._resolved) {
2422
- this.pendingPlayState = "running";
2423
- return;
2424
- }
2425
- if (this.isStopped)
2426
- return;
2427
- const { driver = frameloopDriver, onPlay, startTime } = this.options;
2428
- if (!this.driver) {
2429
- this.driver = driver((timestamp) => this.tick(timestamp));
2430
- }
2431
- onPlay && onPlay();
2432
- const now = this.driver.now();
2433
- if (this.holdTime !== null) {
2434
- this.startTime = now - this.holdTime;
2435
- }
2436
- else if (!this.startTime) {
2437
- this.startTime = startTime ?? this.calcStartTime();
2438
- }
2439
- else if (this.state === "finished") {
2440
- this.startTime = now;
2441
- }
2442
- if (this.state === "finished") {
2443
- this.updateFinishedPromise();
2444
- }
2445
- this.cancelTime = this.startTime;
2446
- this.holdTime = null;
2447
- /**
2448
- * Set playState to running only after we've used it in
2449
- * the previous logic.
2450
- */
2451
- this.state = "running";
2452
- this.driver.start();
2453
- }
2454
- pause() {
2455
- if (!this._resolved) {
2456
- this.pendingPlayState = "paused";
2457
- return;
2458
- }
2459
- this.state = "paused";
2460
- this.holdTime = this.currentTime ?? 0;
2461
- }
2462
- complete() {
2463
- if (this.state !== "running") {
2464
- this.play();
2465
- }
2466
- this.pendingPlayState = this.state = "finished";
2467
- this.holdTime = null;
2468
- }
2469
- finish() {
2470
- this.teardown();
2471
- this.state = "finished";
2472
- const { onComplete } = this.options;
2473
- onComplete && onComplete();
2474
- }
2475
- cancel() {
2476
- if (this.cancelTime !== null) {
2477
- this.tick(this.cancelTime);
2478
- }
2479
- this.teardown();
2480
- this.updateFinishedPromise();
2481
- }
2482
- teardown() {
2483
- this.state = "idle";
2484
- this.stopDriver();
2485
- this.resolveFinishedPromise();
2486
- this.updateFinishedPromise();
2487
- this.startTime = this.cancelTime = null;
2488
- this.resolver.cancel();
2489
- motionDom.activeAnimations.mainThread--;
2490
- }
2491
- stopDriver() {
2492
- if (!this.driver)
2493
- return;
2494
- this.driver.stop();
2495
- this.driver = undefined;
2496
- }
2497
- sample(time) {
2498
- this.startTime = 0;
2499
- return this.tick(time, true);
2500
- }
2501
- get finished() {
2502
- return this.currentFinishedPromise;
2503
- }
150
+ function calcRelativeAxisPosition(target, layout, parent) {
151
+ target.min = layout.min - parent.min;
152
+ target.max = target.min + calcLength(layout);
2504
153
  }
2505
- // Legacy interface
2506
- function animateValue(options) {
2507
- return new MainThreadAnimation(options);
154
+ function calcRelativePosition(target, layout, parent) {
155
+ calcRelativeAxisPosition(target.x, layout.x, parent.x);
156
+ calcRelativeAxisPosition(target.y, layout.y, parent.y);
2508
157
  }
2509
158
 
2510
- /**
2511
- * A list of values that can be hardware-accelerated.
2512
- */
2513
- const acceleratedValues = new Set([
2514
- "opacity",
2515
- "clipPath",
2516
- "filter",
2517
- "transform",
2518
- // TODO: Can be accelerated but currently disabled until https://issues.chromium.org/issues/41491098 is resolved
2519
- // or until we implement support for linear() easing.
2520
- // "background-color"
2521
- ]);
2522
-
2523
- const supportsWaapi = /*@__PURE__*/ motionUtils.memo(() => Object.hasOwnProperty.call(Element.prototype, "animate"));
159
+ const isMotionValue = (value) => Boolean(value && value.getVelocity);
2524
160
 
2525
- /**
2526
- * 10ms is chosen here as it strikes a balance between smooth
2527
- * results (more than one keyframe per frame at 60fps) and
2528
- * keyframe quantity.
2529
- */
2530
- const sampleDelta = 10; //ms
2531
- /**
2532
- * Implement a practical max duration for keyframe generation
2533
- * to prevent infinite loops
2534
- */
2535
- const maxDuration = 20000;
2536
- /**
2537
- * Check if an animation can run natively via WAAPI or requires pregenerated keyframes.
2538
- * WAAPI doesn't support spring or function easings so we run these as JS animation before
2539
- * handing off.
2540
- */
2541
- function requiresPregeneratedKeyframes(options) {
2542
- return (motionDom.isGenerator(options.type) ||
2543
- options.type === "spring" ||
2544
- !motionDom.isWaapiSupportedEasing(options.ease));
2545
- }
2546
- function pregenerateKeyframes(keyframes, options) {
2547
- /**
2548
- * Create a main-thread animation to pregenerate keyframes.
2549
- * We sample this at regular intervals to generate keyframes that we then
2550
- * linearly interpolate between.
2551
- */
2552
- const sampleAnimation = new MainThreadAnimation({
2553
- ...options,
2554
- keyframes,
2555
- repeat: 0,
2556
- delay: 0,
2557
- isGenerator: true,
2558
- });
2559
- let state = { done: false, value: keyframes[0] };
2560
- const pregeneratedKeyframes = [];
2561
- /**
2562
- * Bail after 20 seconds of pre-generated keyframes as it's likely
2563
- * we're heading for an infinite loop.
2564
- */
2565
- let t = 0;
2566
- while (!state.done && t < maxDuration) {
2567
- state = sampleAnimation.sample(t);
2568
- pregeneratedKeyframes.push(state.value);
2569
- t += sampleDelta;
2570
- }
2571
- return {
2572
- times: undefined,
2573
- keyframes: pregeneratedKeyframes,
2574
- duration: t - sampleDelta,
2575
- ease: "linear",
2576
- };
2577
- }
2578
- const unsupportedEasingFunctions = {
2579
- anticipate,
2580
- backInOut,
2581
- circInOut,
2582
- };
2583
- function isUnsupportedEase(key) {
2584
- return key in unsupportedEasingFunctions;
2585
- }
2586
- class AcceleratedAnimation extends BaseAnimation {
2587
- constructor(options) {
2588
- super(options);
2589
- const { name, motionValue, element, keyframes } = this.options;
2590
- this.resolver = new DOMKeyframesResolver(keyframes, (resolvedKeyframes, finalKeyframe) => this.onKeyframesResolved(resolvedKeyframes, finalKeyframe), name, motionValue, element);
2591
- this.resolver.scheduleResolve();
2592
- }
2593
- initPlayback(keyframes, finalKeyframe) {
2594
- let { duration = 300, times, ease, type, motionValue, name, startTime, } = this.options;
2595
- /**
2596
- * If element has since been unmounted, return false to indicate
2597
- * the animation failed to initialised.
2598
- */
2599
- if (!motionValue.owner || !motionValue.owner.current) {
2600
- return false;
2601
- }
2602
- /**
2603
- * If the user has provided an easing function name that isn't supported
2604
- * by WAAPI (like "anticipate"), we need to provide the corressponding
2605
- * function. This will later get converted to a linear() easing function.
2606
- */
2607
- if (typeof ease === "string" &&
2608
- motionDom.supportsLinearEasing() &&
2609
- isUnsupportedEase(ease)) {
2610
- ease = unsupportedEasingFunctions[ease];
2611
- }
2612
- /**
2613
- * If this animation needs pre-generated keyframes then generate.
2614
- */
2615
- if (requiresPregeneratedKeyframes(this.options)) {
2616
- const { onComplete, onUpdate, motionValue, element, ...options } = this.options;
2617
- const pregeneratedAnimation = pregenerateKeyframes(keyframes, options);
2618
- keyframes = pregeneratedAnimation.keyframes;
2619
- // If this is a very short animation, ensure we have
2620
- // at least two keyframes to animate between as older browsers
2621
- // can't animate between a single keyframe.
2622
- if (keyframes.length === 1) {
2623
- keyframes[1] = keyframes[0];
2624
- }
2625
- duration = pregeneratedAnimation.duration;
2626
- times = pregeneratedAnimation.times;
2627
- ease = pregeneratedAnimation.ease;
2628
- type = "keyframes";
2629
- }
2630
- const animation = motionDom.startWaapiAnimation(motionValue.owner.current, name, keyframes, { ...this.options, duration, times, ease });
2631
- // Override the browser calculated startTime with one synchronised to other JS
2632
- // and WAAPI animations starting this event loop.
2633
- animation.startTime = startTime ?? this.calcStartTime();
2634
- if (this.pendingTimeline) {
2635
- motionDom.attachTimeline(animation, this.pendingTimeline);
2636
- this.pendingTimeline = undefined;
2637
- }
2638
- else {
2639
- /**
2640
- * Prefer the `onfinish` prop as it's more widely supported than
2641
- * the `finished` promise.
2642
- *
2643
- * Here, we synchronously set the provided MotionValue to the end
2644
- * keyframe. If we didn't, when the WAAPI animation is finished it would
2645
- * be removed from the element which would then revert to its old styles.
2646
- */
2647
- animation.onfinish = () => {
2648
- const { onComplete } = this.options;
2649
- motionValue.set(getFinalKeyframe(keyframes, this.options, finalKeyframe));
2650
- onComplete && onComplete();
2651
- this.cancel();
2652
- this.resolveFinishedPromise();
2653
- };
2654
- }
2655
- return {
2656
- animation,
2657
- duration,
2658
- times,
2659
- type,
2660
- ease,
2661
- keyframes: keyframes,
2662
- };
2663
- }
2664
- get duration() {
2665
- const { resolved } = this;
2666
- if (!resolved)
2667
- return 0;
2668
- const { duration } = resolved;
2669
- return motionUtils.millisecondsToSeconds(duration);
2670
- }
2671
- get time() {
2672
- const { resolved } = this;
2673
- if (!resolved)
2674
- return 0;
2675
- const { animation } = resolved;
2676
- return motionUtils.millisecondsToSeconds(animation.currentTime || 0);
2677
- }
2678
- set time(newTime) {
2679
- const { resolved } = this;
2680
- if (!resolved)
2681
- return;
2682
- const { animation } = resolved;
2683
- animation.currentTime = motionUtils.secondsToMilliseconds(newTime);
2684
- }
2685
- get speed() {
2686
- const { resolved } = this;
2687
- if (!resolved)
2688
- return 1;
2689
- const { animation } = resolved;
2690
- return animation.playbackRate;
2691
- }
2692
- get finished() {
2693
- return this.resolved.animation.finished;
2694
- }
2695
- set speed(newSpeed) {
2696
- const { resolved } = this;
2697
- if (!resolved)
2698
- return;
2699
- const { animation } = resolved;
2700
- animation.playbackRate = newSpeed;
2701
- }
2702
- get state() {
2703
- const { resolved } = this;
2704
- if (!resolved)
2705
- return "idle";
2706
- const { animation } = resolved;
2707
- return animation.playState;
2708
- }
2709
- get startTime() {
2710
- const { resolved } = this;
2711
- if (!resolved)
2712
- return null;
2713
- const { animation } = resolved;
2714
- // Coerce to number as TypeScript incorrectly types this
2715
- // as CSSNumberish
2716
- return animation.startTime;
2717
- }
2718
- /**
2719
- * Replace the default DocumentTimeline with another AnimationTimeline.
2720
- * Currently used for scroll animations.
2721
- */
2722
- attachTimeline(timeline) {
2723
- if (!this._resolved) {
2724
- this.pendingTimeline = timeline;
2725
- }
2726
- else {
2727
- const { resolved } = this;
2728
- if (!resolved)
2729
- return motionUtils.noop;
2730
- const { animation } = resolved;
2731
- motionDom.attachTimeline(animation, timeline);
2732
- }
2733
- return motionUtils.noop;
2734
- }
2735
- play() {
2736
- if (this.isStopped)
2737
- return;
2738
- const { resolved } = this;
2739
- if (!resolved)
2740
- return;
2741
- const { animation } = resolved;
2742
- if (animation.playState === "finished") {
2743
- this.updateFinishedPromise();
2744
- }
2745
- animation.play();
2746
- }
2747
- pause() {
2748
- const { resolved } = this;
2749
- if (!resolved)
2750
- return;
2751
- const { animation } = resolved;
2752
- animation.pause();
2753
- }
2754
- stop() {
2755
- this.resolver.cancel();
2756
- this.isStopped = true;
2757
- if (this.state === "idle")
2758
- return;
2759
- this.resolveFinishedPromise();
2760
- this.updateFinishedPromise();
2761
- const { resolved } = this;
2762
- if (!resolved)
2763
- return;
2764
- const { animation, keyframes, duration, type, ease, times } = resolved;
2765
- if (animation.playState === "idle" ||
2766
- animation.playState === "finished") {
2767
- return;
2768
- }
2769
- /**
2770
- * WAAPI doesn't natively have any interruption capabilities.
2771
- *
2772
- * Rather than read commited styles back out of the DOM, we can
2773
- * create a renderless JS animation and sample it twice to calculate
2774
- * its current value, "previous" value, and therefore allow
2775
- * Motion to calculate velocity for any subsequent animation.
2776
- */
2777
- if (this.time) {
2778
- const { motionValue, onUpdate, onComplete, element, ...options } = this.options;
2779
- const sampleAnimation = new MainThreadAnimation({
2780
- ...options,
2781
- keyframes,
2782
- duration,
2783
- type,
2784
- ease,
2785
- times,
2786
- isGenerator: true,
2787
- });
2788
- const sampleTime = motionUtils.secondsToMilliseconds(this.time);
2789
- motionValue.setWithVelocity(sampleAnimation.sample(sampleTime - sampleDelta).value, sampleAnimation.sample(sampleTime).value, sampleDelta);
2790
- }
2791
- const { onStop } = this.options;
2792
- onStop && onStop();
2793
- this.cancel();
2794
- }
2795
- complete() {
2796
- const { resolved } = this;
2797
- if (!resolved)
2798
- return;
2799
- resolved.animation.finish();
2800
- }
2801
- cancel() {
2802
- const { resolved } = this;
2803
- if (!resolved)
2804
- return;
2805
- resolved.animation.cancel();
2806
- }
2807
- static supports(options) {
2808
- const { motionValue, name, repeatDelay, repeatType, damping, type } = options;
2809
- if (!motionValue ||
2810
- !motionValue.owner ||
2811
- !(motionValue.owner.current instanceof HTMLElement)) {
2812
- return false;
2813
- }
2814
- const { onUpdate, transformTemplate } = motionValue.owner.getProps();
2815
- return (supportsWaapi() &&
2816
- name &&
2817
- acceleratedValues.has(name) &&
2818
- (name !== "transform" || !transformTemplate) &&
2819
- /**
2820
- * If we're outputting values to onUpdate then we can't use WAAPI as there's
2821
- * no way to read the value from WAAPI every frame.
2822
- */
2823
- !onUpdate &&
2824
- !repeatDelay &&
2825
- repeatType !== "mirror" &&
2826
- damping !== 0 &&
2827
- type !== "inertia");
2828
- }
161
+ const isNotNull = (value) => value !== null;
162
+ function getFinalKeyframe(keyframes, { repeat, repeatType = "loop" }, finalKeyframe) {
163
+ const resolvedKeyframes = keyframes.filter(isNotNull);
164
+ const index = repeat && repeatType !== "loop" && repeat % 2 === 1
165
+ ? 0
166
+ : resolvedKeyframes.length - 1;
167
+ return !index || finalKeyframe === undefined
168
+ ? resolvedKeyframes[index]
169
+ : finalKeyframe;
2829
170
  }
2830
171
 
2831
172
  const underDampedSpring = {
@@ -2857,7 +198,7 @@ const getDefaultTransition = (valueKey, { keyframes }) => {
2857
198
  if (keyframes.length > 2) {
2858
199
  return keyframesTransition;
2859
200
  }
2860
- else if (transformProps.has(valueKey)) {
201
+ else if (motionDom.transformProps.has(valueKey)) {
2861
202
  return valueKey.startsWith("scale")
2862
203
  ? criticallyDampedSpring(keyframes[1])
2863
204
  : underDampedSpring;
@@ -2888,7 +229,7 @@ const animateMotionValue = (name, value, target, transition = {}, element, isHan
2888
229
  */
2889
230
  let { elapsed = 0 } = transition;
2890
231
  elapsed = elapsed - motionUtils.secondsToMilliseconds(delay);
2891
- let options = {
232
+ const options = {
2892
233
  keyframes: Array.isArray(target) ? target : [null, target],
2893
234
  ease: "easeOut",
2894
235
  velocity: value.getVelocity(),
@@ -2911,22 +252,18 @@ const animateMotionValue = (name, value, target, transition = {}, element, isHan
2911
252
  * unique transition settings for this value.
2912
253
  */
2913
254
  if (!isTransitionDefined(valueTransition)) {
2914
- options = {
2915
- ...options,
2916
- ...getDefaultTransition(name, options),
2917
- };
255
+ Object.assign(options, getDefaultTransition(name, options));
2918
256
  }
2919
257
  /**
2920
258
  * Both WAAPI and our internal animation functions use durations
2921
259
  * as defined by milliseconds, while our external API defines them
2922
260
  * as seconds.
2923
261
  */
2924
- if (options.duration) {
2925
- options.duration = motionUtils.secondsToMilliseconds(options.duration);
2926
- }
2927
- if (options.repeatDelay) {
2928
- options.repeatDelay = motionUtils.secondsToMilliseconds(options.repeatDelay);
2929
- }
262
+ options.duration && (options.duration = motionUtils.secondsToMilliseconds(options.duration));
263
+ options.repeatDelay && (options.repeatDelay = motionUtils.secondsToMilliseconds(options.repeatDelay));
264
+ /**
265
+ * Support deprecated way to set initial value. Prefer keyframe syntax.
266
+ */
2930
267
  if (options.from !== undefined) {
2931
268
  options.keyframes[0] = options.from;
2932
269
  }
@@ -2938,7 +275,7 @@ const animateMotionValue = (name, value, target, transition = {}, element, isHan
2938
275
  shouldSkip = true;
2939
276
  }
2940
277
  }
2941
- if (instantAnimationState.current ||
278
+ if (motionUtils.MotionGlobalConfig.instantAnimations ||
2942
279
  motionUtils.MotionGlobalConfig.skipAnimations) {
2943
280
  shouldSkip = true;
2944
281
  options.duration = 0;
@@ -2961,22 +298,10 @@ const animateMotionValue = (name, value, target, transition = {}, element, isHan
2961
298
  options.onUpdate(finalKeyframe);
2962
299
  options.onComplete();
2963
300
  });
2964
- // We still want to return some animation controls here rather
2965
- // than returning undefined
2966
- return new motionDom.GroupAnimationWithThen([]);
301
+ return;
2967
302
  }
2968
303
  }
2969
- /**
2970
- * Animate via WAAPI if possible. If this is a handoff animation, the optimised animation will be running via
2971
- * WAAPI. Therefore, this animation must be JS to ensure it runs "under" the
2972
- * optimised animation.
2973
- */
2974
- if (!isHandoff && AcceleratedAnimation.supports(options)) {
2975
- return new AcceleratedAnimation(options);
2976
- }
2977
- else {
2978
- return new MainThreadAnimation(options);
2979
- }
304
+ return new motionDom.AsyncMotionValueAnimation(options);
2980
305
  };
2981
306
 
2982
307
  function animateSingleValue(value, keyframes, options) {
@@ -3035,7 +360,7 @@ function delay(callback, timeout) {
3035
360
  callback(elapsed - timeout);
3036
361
  }
3037
362
  };
3038
- motionDom.frame.read(checkElapsed, true);
363
+ motionDom.frame.setup(checkElapsed, true);
3039
364
  return () => motionDom.cancelFrame(checkElapsed);
3040
365
  }
3041
366
 
@@ -3066,14 +391,14 @@ function resolveMotionValue(value) {
3066
391
  const borders = ["TopLeft", "TopRight", "BottomLeft", "BottomRight"];
3067
392
  const numBorders = borders.length;
3068
393
  const asNumber = (value) => typeof value === "string" ? parseFloat(value) : value;
3069
- const isPx = (value) => typeof value === "number" || px.test(value);
394
+ const isPx = (value) => typeof value === "number" || motionDom.px.test(value);
3070
395
  function mixValues(target, follow, lead, progress, shouldCrossfadeOpacity, isOnlyMember) {
3071
396
  if (shouldCrossfadeOpacity) {
3072
- target.opacity = mixNumber$1(0, lead.opacity ?? 1, easeCrossfadeIn(progress));
3073
- target.opacityExit = mixNumber$1(follow.opacity ?? 1, 0, easeCrossfadeOut(progress));
397
+ target.opacity = motionDom.mixNumber(0, lead.opacity ?? 1, easeCrossfadeIn(progress));
398
+ target.opacityExit = motionDom.mixNumber(follow.opacity ?? 1, 0, easeCrossfadeOut(progress));
3074
399
  }
3075
400
  else if (isOnlyMember) {
3076
- target.opacity = mixNumber$1(follow.opacity ?? 1, lead.opacity ?? 1, progress);
401
+ target.opacity = motionDom.mixNumber(follow.opacity ?? 1, lead.opacity ?? 1, progress);
3077
402
  }
3078
403
  /**
3079
404
  * Mix border radius
@@ -3090,8 +415,8 @@ function mixValues(target, follow, lead, progress, shouldCrossfadeOpacity, isOnl
3090
415
  leadRadius === 0 ||
3091
416
  isPx(followRadius) === isPx(leadRadius);
3092
417
  if (canMix) {
3093
- target[borderLabel] = Math.max(mixNumber$1(asNumber(followRadius), asNumber(leadRadius), progress), 0);
3094
- if (percent.test(leadRadius) || percent.test(followRadius)) {
418
+ target[borderLabel] = Math.max(motionDom.mixNumber(asNumber(followRadius), asNumber(leadRadius), progress), 0);
419
+ if (motionDom.percent.test(leadRadius) || motionDom.percent.test(followRadius)) {
3095
420
  target[borderLabel] += "%";
3096
421
  }
3097
422
  }
@@ -3103,7 +428,7 @@ function mixValues(target, follow, lead, progress, shouldCrossfadeOpacity, isOnl
3103
428
  * Mix rotation
3104
429
  */
3105
430
  if (follow.rotate || lead.rotate) {
3106
- target.rotate = mixNumber$1(follow.rotate || 0, lead.rotate || 0, progress);
431
+ target.rotate = motionDom.mixNumber(follow.rotate || 0, lead.rotate || 0, progress);
3107
432
  }
3108
433
  }
3109
434
  function getRadius(values, radiusName) {
@@ -3134,7 +459,7 @@ function getRadius(values, radiusName) {
3134
459
  // latestLeadValues.backgroundColor as string
3135
460
  // )(p)
3136
461
  // }
3137
- const easeCrossfadeIn = /*@__PURE__*/ compress(0, 0.5, circOut);
462
+ const easeCrossfadeIn = /*@__PURE__*/ compress(0, 0.5, motionUtils.circOut);
3138
463
  const easeCrossfadeOut = /*@__PURE__*/ compress(0.5, 0.95, motionUtils.noop);
3139
464
  function compress(min, max, easing) {
3140
465
  return (p) => {
@@ -3305,7 +630,7 @@ function translateAxis(axis, distance) {
3305
630
  * and applyAxisDelta
3306
631
  */
3307
632
  function transformAxis(axis, axisTranslate, axisScale, boxScale, axisOrigin = 0.5) {
3308
- const originPoint = mixNumber$1(axis.min, axis.max, axisOrigin);
633
+ const originPoint = motionDom.mixNumber(axis.min, axis.max, axisOrigin);
3309
634
  // Apply the axis delta to the final axis
3310
635
  applyAxisDelta(axis, axisTranslate, axisScale, originPoint, boxScale);
3311
636
  }
@@ -3332,14 +657,14 @@ function removePointDelta(point, translate, scale, originPoint, boxScale) {
3332
657
  * Remove a delta from an axis. This is essentially the steps of applyAxisDelta in reverse
3333
658
  */
3334
659
  function removeAxisDelta(axis, translate = 0, scale = 1, origin = 0.5, boxScale, originAxis = axis, sourceAxis = axis) {
3335
- if (percent.test(translate)) {
660
+ if (motionDom.percent.test(translate)) {
3336
661
  translate = parseFloat(translate);
3337
- const relativeProgress = mixNumber$1(sourceAxis.min, sourceAxis.max, translate / 100);
662
+ const relativeProgress = motionDom.mixNumber(sourceAxis.min, sourceAxis.max, translate / 100);
3338
663
  translate = relativeProgress - sourceAxis.min;
3339
664
  }
3340
665
  if (typeof translate !== "number")
3341
666
  return;
3342
- let originPoint = mixNumber$1(originAxis.min, originAxis.max, origin);
667
+ let originPoint = motionDom.mixNumber(originAxis.min, originAxis.max, origin);
3343
668
  if (axis === originAxis)
3344
669
  originPoint -= translate;
3345
670
  axis.min = removePointDelta(axis.min, translate, scale, originPoint, boxScale);
@@ -3523,7 +848,7 @@ const scaleCorrectors = {};
3523
848
  function addScaleCorrector(correctors) {
3524
849
  for (const key in correctors) {
3525
850
  scaleCorrectors[key] = correctors[key];
3526
- if (isCSSVariableName(key)) {
851
+ if (motionDom.isCSSVariableName(key)) {
3527
852
  scaleCorrectors[key].isCSSVariable = true;
3528
853
  }
3529
854
  }
@@ -4029,7 +1354,7 @@ function createProjectionNode$1({ attachResizeListener, defaultParent, measureSc
4029
1354
  * to leave a flash of incorrectly styled content.
4030
1355
  */
4031
1356
  const now = motionDom.time.now();
4032
- motionDom.frameData.delta = clamp(0, 1000 / 60, now - motionDom.frameData.timestamp);
1357
+ motionDom.frameData.delta = motionUtils.clamp(0, 1000 / 60, now - motionDom.frameData.timestamp);
4033
1358
  motionDom.frameData.timestamp = now;
4034
1359
  motionDom.frameData.isProcessing = true;
4035
1360
  motionDom.frameSteps.update.process(motionDom.frameData);
@@ -4571,9 +1896,7 @@ function createProjectionNode$1({ attachResizeListener, defaultParent, measureSc
4571
1896
  }
4572
1897
  setAnimationOrigin(delta, hasOnlyRelativeTargetChanged = false) {
4573
1898
  const snapshot = this.snapshot;
4574
- const snapshotLatestValues = snapshot
4575
- ? snapshot.latestValues
4576
- : {};
1899
+ const snapshotLatestValues = snapshot ? snapshot.latestValues : {};
4577
1900
  const mixedValues = { ...this.latestValues };
4578
1901
  const targetDelta = createDelta();
4579
1902
  if (!this.relativeParent ||
@@ -5117,14 +2440,14 @@ function removeLeadSnapshots(stack) {
5117
2440
  stack.removeLeadSnapshot();
5118
2441
  }
5119
2442
  function mixAxisDelta(output, delta, p) {
5120
- output.translate = mixNumber$1(delta.translate, 0, p);
5121
- output.scale = mixNumber$1(delta.scale, 1, p);
2443
+ output.translate = motionDom.mixNumber(delta.translate, 0, p);
2444
+ output.scale = motionDom.mixNumber(delta.scale, 1, p);
5122
2445
  output.origin = delta.origin;
5123
2446
  output.originPoint = delta.originPoint;
5124
2447
  }
5125
2448
  function mixAxis(output, from, to, p) {
5126
- output.min = mixNumber$1(from.min, to.min, p);
5127
- output.max = mixNumber$1(from.max, to.max, p);
2449
+ output.min = motionDom.mixNumber(from.min, to.min, p);
2450
+ output.max = motionDom.mixNumber(from.max, to.max, p);
5128
2451
  }
5129
2452
  function mixBox(output, from, to, p) {
5130
2453
  mixAxis(output.x, from.x, to.x, p);
@@ -5224,7 +2547,7 @@ const correctBorderRadius = {
5224
2547
  * going to be stretched appropriately. Otherwise, if it's a pixel, convert it to a number.
5225
2548
  */
5226
2549
  if (typeof latest === "string") {
5227
- if (px.test(latest)) {
2550
+ if (motionDom.px.test(latest)) {
5228
2551
  latest = parseFloat(latest);
5229
2552
  }
5230
2553
  else {
@@ -5244,11 +2567,11 @@ const correctBorderRadius = {
5244
2567
  const correctBoxShadow = {
5245
2568
  correct: (latest, { treeScale, projectionDelta }) => {
5246
2569
  const original = latest;
5247
- const shadow = complex.parse(latest);
2570
+ const shadow = motionDom.complex.parse(latest);
5248
2571
  // TODO: Doesn't support multiple shadows
5249
2572
  if (shadow.length > 5)
5250
2573
  return original;
5251
- const template = complex.createTransformer(latest);
2574
+ const template = motionDom.complex.createTransformer(latest);
5252
2575
  const offset = typeof shadow[0] !== "number" ? 1 : 0;
5253
2576
  // Calculate the overall context scale
5254
2577
  const xScale = projectionDelta.x.scale * treeScale.x;
@@ -5261,7 +2584,7 @@ const correctBoxShadow = {
5261
2584
  * We could potentially improve the outcome of this by incorporating the ratio between
5262
2585
  * the two scales.
5263
2586
  */
5264
- const averageScale = mixNumber$1(xScale, yScale, 0.5);
2587
+ const averageScale = motionDom.mixNumber(xScale, yScale, 0.5);
5265
2588
  // Blur
5266
2589
  if (typeof shadow[2 + offset] === "number")
5267
2590
  shadow[2 + offset] /= averageScale;
@@ -5363,15 +2686,6 @@ function initPrefersReducedMotion() {
5363
2686
  }
5364
2687
  }
5365
2688
 
5366
- /**
5367
- * A list of all ValueTypes
5368
- */
5369
- const valueTypes = [...dimensionValueTypes, color, complex];
5370
- /**
5371
- * Tests a value against the list of ValueTypes
5372
- */
5373
- const findValueType = (v) => valueTypes.find(testValueType(v));
5374
-
5375
2689
  const visualElementStore = new WeakMap();
5376
2690
 
5377
2691
  function isAnimationControls(v) {
@@ -5421,7 +2735,7 @@ function updateMotionValuesFromProps(element, next, prev) {
5421
2735
  * and warn against mismatches.
5422
2736
  */
5423
2737
  if (process.env.NODE_ENV === "development") {
5424
- motionUtils.warnOnce(nextValue.version === "12.7.3", `Attempting to mix Motion versions ${nextValue.version} with 12.7.3 may not work as expected.`);
2738
+ motionUtils.warnOnce(nextValue.version === "12.7.5-alpha.0", `Attempting to mix Motion versions ${nextValue.version} with 12.7.5-alpha.0 may not work as expected.`);
5425
2739
  }
5426
2740
  }
5427
2741
  else if (isMotionValue(prevValue)) {
@@ -5548,7 +2862,7 @@ class VisualElement {
5548
2862
  * value might be provided externally by the component via props.
5549
2863
  */
5550
2864
  this.values = new Map();
5551
- this.KeyframeResolver = KeyframeResolver;
2865
+ this.KeyframeResolver = motionDom.KeyframeResolver;
5552
2866
  /**
5553
2867
  * Cleanup functions for active features (hover/tap/exit etc)
5554
2868
  */
@@ -5676,7 +2990,7 @@ class VisualElement {
5676
2990
  if (this.valueSubscriptions.has(key)) {
5677
2991
  this.valueSubscriptions.get(key)();
5678
2992
  }
5679
- const valueIsTransform = transformProps.has(key);
2993
+ const valueIsTransform = motionDom.transformProps.has(key);
5680
2994
  if (valueIsTransform && this.onBindTransform) {
5681
2995
  this.onBindTransform();
5682
2996
  }
@@ -5886,12 +3200,12 @@ class VisualElement {
5886
3200
  this.readValueFromInstance(this.current, key, this.options);
5887
3201
  if (value !== undefined && value !== null) {
5888
3202
  if (typeof value === "string" &&
5889
- (isNumericalString(value) || isZeroValueString(value))) {
3203
+ (motionUtils.isNumericalString(value) || motionUtils.isZeroValueString(value))) {
5890
3204
  // If this is a number read as a string, ie "0" or "200", convert it to a number
5891
3205
  value = parseFloat(value);
5892
3206
  }
5893
- else if (!findValueType(value) && complex.test(target)) {
5894
- value = getAnimatableNone(key, target);
3207
+ else if (!motionDom.findValueType(value) && motionDom.complex.test(target)) {
3208
+ value = motionDom.getAnimatableNone(key, target);
5895
3209
  }
5896
3210
  this.setBaseTarget(key, isMotionValue(value) ? value.get() : value);
5897
3211
  }
@@ -5955,7 +3269,7 @@ class VisualElement {
5955
3269
  class DOMVisualElement extends VisualElement {
5956
3270
  constructor() {
5957
3271
  super(...arguments);
5958
- this.KeyframeResolver = DOMKeyframesResolver;
3272
+ this.KeyframeResolver = motionDom.DOMKeyframesResolver;
5959
3273
  }
5960
3274
  sortInstanceNodePosition(a, b) {
5961
3275
  /**
@@ -5990,22 +3304,13 @@ class DOMVisualElement extends VisualElement {
5990
3304
  }
5991
3305
  }
5992
3306
 
5993
- /**
5994
- * Provided a value and a ValueType, returns the value as that value type.
5995
- */
5996
- const getValueAsType = (value, type) => {
5997
- return type && typeof value === "number"
5998
- ? type.transform(value)
5999
- : value;
6000
- };
6001
-
6002
3307
  const translateAlias = {
6003
3308
  x: "translateX",
6004
3309
  y: "translateY",
6005
3310
  z: "translateZ",
6006
3311
  transformPerspective: "perspective",
6007
3312
  };
6008
- const numTransforms = transformPropOrder.length;
3313
+ const numTransforms = motionDom.transformPropOrder.length;
6009
3314
  /**
6010
3315
  * Build a CSS transform style from individual x/y/scale etc properties.
6011
3316
  *
@@ -6021,7 +3326,7 @@ function buildTransform(latestValues, transform, transformTemplate) {
6021
3326
  * are present to the transform string.
6022
3327
  */
6023
3328
  for (let i = 0; i < numTransforms; i++) {
6024
- const key = transformPropOrder[i];
3329
+ const key = motionDom.transformPropOrder[i];
6025
3330
  const value = latestValues[key];
6026
3331
  if (value === undefined)
6027
3332
  continue;
@@ -6033,7 +3338,7 @@ function buildTransform(latestValues, transform, transformTemplate) {
6033
3338
  valueIsDefault = parseFloat(value) === 0;
6034
3339
  }
6035
3340
  if (!valueIsDefault || transformTemplate) {
6036
- const valueAsType = getValueAsType(value, numberValueTypes[key]);
3341
+ const valueAsType = motionDom.getValueAsType(value, motionDom.numberValueTypes[key]);
6037
3342
  if (!valueIsDefault) {
6038
3343
  transformIsDefault = false;
6039
3344
  const transformName = translateAlias[key] || key;
@@ -6069,18 +3374,18 @@ function buildHTMLStyles(state, latestValues, transformTemplate) {
6069
3374
  */
6070
3375
  for (const key in latestValues) {
6071
3376
  const value = latestValues[key];
6072
- if (transformProps.has(key)) {
3377
+ if (motionDom.transformProps.has(key)) {
6073
3378
  // If this is a transform, flag to enable further transform processing
6074
3379
  hasTransform = true;
6075
3380
  continue;
6076
3381
  }
6077
- else if (isCSSVariableName(key)) {
3382
+ else if (motionDom.isCSSVariableName(key)) {
6078
3383
  vars[key] = value;
6079
3384
  continue;
6080
3385
  }
6081
3386
  else {
6082
3387
  // Convert the value to its default value type, ie 0 -> "0px"
6083
- const valueAsType = getValueAsType(value, numberValueTypes[key]);
3388
+ const valueAsType = motionDom.getValueAsType(value, motionDom.numberValueTypes[key]);
6084
3389
  if (key.startsWith("origin")) {
6085
3390
  // If this is a transform origin, flag and enable further transform-origin processing
6086
3391
  hasTransformOrigin = true;
@@ -6123,7 +3428,7 @@ function renderHTML(element, { style, vars }, styleProp, projection) {
6123
3428
  }
6124
3429
 
6125
3430
  function isForcedMotionValue(key, { layout, layoutId }) {
6126
- return (transformProps.has(key) ||
3431
+ return (motionDom.transformProps.has(key) ||
6127
3432
  key.startsWith("origin") ||
6128
3433
  ((layout || layoutId !== undefined) &&
6129
3434
  (!!scaleCorrectors[key] || key === "opacity")));
@@ -6144,7 +3449,7 @@ function scrapeMotionValuesFromProps$1(props, prevProps, visualElement) {
6144
3449
  return newValues;
6145
3450
  }
6146
3451
 
6147
- function getComputedStyle$1(element) {
3452
+ function getComputedStyle(element) {
6148
3453
  return window.getComputedStyle(element);
6149
3454
  }
6150
3455
  class HTMLVisualElement extends DOMVisualElement {
@@ -6154,12 +3459,12 @@ class HTMLVisualElement extends DOMVisualElement {
6154
3459
  this.renderInstance = renderHTML;
6155
3460
  }
6156
3461
  readValueFromInstance(instance, key) {
6157
- if (transformProps.has(key)) {
6158
- return readTransformValue(instance, key);
3462
+ if (motionDom.transformProps.has(key)) {
3463
+ return motionDom.readTransformValue(instance, key);
6159
3464
  }
6160
3465
  else {
6161
- const computedStyle = getComputedStyle$1(instance);
6162
- const value = (isCSSVariableName(key)
3466
+ const computedStyle = getComputedStyle(instance);
3467
+ const value = (motionDom.isCSSVariableName(key)
6163
3468
  ? computedStyle.getPropertyValue(key)
6164
3469
  : computedStyle[key]) || 0;
6165
3470
  return typeof value === "string" ? value.trim() : value;
@@ -6393,7 +3698,7 @@ function animateTarget(visualElement, targetAndTransition, { delay = 0, transiti
6393
3698
  }
6394
3699
  }
6395
3700
  addValueToWillChange(visualElement, key);
6396
- value.start(animateMotionValue(key, value, valueTarget, visualElement.shouldReduceMotion && positionalKeys.has(key)
3701
+ value.start(animateMotionValue(key, value, valueTarget, visualElement.shouldReduceMotion && motionDom.positionalKeys.has(key)
6397
3702
  ? { type: false }
6398
3703
  : valueTransition, visualElement, isHandoff));
6399
3704
  const animation = value.animation;
@@ -7064,7 +4369,7 @@ class PanSession {
7064
4369
  const { onSessionStart } = handlers;
7065
4370
  onSessionStart &&
7066
4371
  onSessionStart(event, getPanInfo(initialInfo, this.history));
7067
- this.removeListeners = pipe(addPointerEvent(this.contextWindow, "pointermove", this.handlePointerMove), addPointerEvent(this.contextWindow, "pointerup", this.handlePointerUp), addPointerEvent(this.contextWindow, "pointercancel", this.handlePointerUp));
4372
+ this.removeListeners = motionUtils.pipe(addPointerEvent(this.contextWindow, "pointermove", this.handlePointerMove), addPointerEvent(this.contextWindow, "pointerup", this.handlePointerUp), addPointerEvent(this.contextWindow, "pointercancel", this.handlePointerUp));
7068
4373
  }
7069
4374
  updateHandlers(handlers) {
7070
4375
  this.handlers = handlers;
@@ -7138,13 +4443,13 @@ function applyConstraints(point, { min, max }, elastic) {
7138
4443
  if (min !== undefined && point < min) {
7139
4444
  // If we have a min point defined, and this is outside of that, constrain
7140
4445
  point = elastic
7141
- ? mixNumber$1(min, point, elastic.min)
4446
+ ? motionDom.mixNumber(min, point, elastic.min)
7142
4447
  : Math.max(point, min);
7143
4448
  }
7144
4449
  else if (max !== undefined && point > max) {
7145
4450
  // If we have a max point defined, and this is outside of that, constrain
7146
4451
  point = elastic
7147
- ? mixNumber$1(max, point, elastic.max)
4452
+ ? motionDom.mixNumber(max, point, elastic.max)
7148
4453
  : Math.min(point, max);
7149
4454
  }
7150
4455
  return point;
@@ -7209,7 +4514,7 @@ function calcOrigin$1(source, target) {
7209
4514
  else if (sourceLength > targetLength) {
7210
4515
  origin = motionUtils.progress(source.min, source.max - targetLength, target.min);
7211
4516
  }
7212
- return clamp(0, 1, origin);
4517
+ return motionUtils.clamp(0, 1, origin);
7213
4518
  }
7214
4519
  /**
7215
4520
  * Rebase the calculated viewport constraints relative to the layout.min point.
@@ -7316,7 +4621,7 @@ class VisualElementDragControls {
7316
4621
  /**
7317
4622
  * If the MotionValue is a percentage value convert to px
7318
4623
  */
7319
- if (percent.test(current)) {
4624
+ if (motionDom.percent.test(current)) {
7320
4625
  const { projection } = this.visualElement;
7321
4626
  if (projection && projection.layout) {
7322
4627
  const measuredAxis = projection.layout.layoutBox[axis];
@@ -7563,7 +4868,7 @@ class VisualElementDragControls {
7563
4868
  const axisValue = this.getAxisMotionValue(axis);
7564
4869
  if (projection && projection.layout) {
7565
4870
  const { min, max } = projection.layout.layoutBox[axis];
7566
- axisValue.set(point[axis] - mixNumber$1(min, max, 0.5));
4871
+ axisValue.set(point[axis] - motionDom.mixNumber(min, max, 0.5));
7567
4872
  }
7568
4873
  });
7569
4874
  }
@@ -7618,7 +4923,7 @@ class VisualElementDragControls {
7618
4923
  */
7619
4924
  const axisValue = this.getAxisMotionValue(axis);
7620
4925
  const { min, max } = this.constraints[axis];
7621
- axisValue.set(mixNumber$1(min, max, boxProgress[axis]));
4926
+ axisValue.set(motionDom.mixNumber(min, max, boxProgress[axis]));
7622
4927
  });
7623
4928
  }
7624
4929
  addListeners() {
@@ -7966,7 +5271,7 @@ class FocusGesture extends Feature {
7966
5271
  this.isActive = false;
7967
5272
  }
7968
5273
  mount() {
7969
- this.unmount = pipe(addDomEvent(this.node.current, "focus", () => this.onFocus()), addDomEvent(this.node.current, "blur", () => this.onBlur()));
5274
+ this.unmount = motionUtils.pipe(addDomEvent(this.node.current, "focus", () => this.onFocus()), addDomEvent(this.node.current, "blur", () => this.onBlur()));
7970
5275
  }
7971
5276
  unmount() { }
7972
5277
  }
@@ -8538,17 +5843,17 @@ function buildSVGPath(attrs, length, spacing = 1, offset = 0, useDashCase = true
8538
5843
  // when defining props on a React component.
8539
5844
  const keys = useDashCase ? dashKeys : camelKeys;
8540
5845
  // Build the dash offset
8541
- attrs[keys.offset] = px.transform(-offset);
5846
+ attrs[keys.offset] = motionDom.px.transform(-offset);
8542
5847
  // Build the dash array
8543
- const pathLength = px.transform(length);
8544
- const pathSpacing = px.transform(spacing);
5848
+ const pathLength = motionDom.px.transform(length);
5849
+ const pathSpacing = motionDom.px.transform(spacing);
8545
5850
  attrs[keys.array] = `${pathLength} ${pathSpacing}`;
8546
5851
  }
8547
5852
 
8548
5853
  function calcOrigin(origin, offset, size) {
8549
5854
  return typeof origin === "string"
8550
5855
  ? origin
8551
- : px.transform(offset + size * origin);
5856
+ : motionDom.px.transform(offset + size * origin);
8552
5857
  }
8553
5858
  /**
8554
5859
  * The SVG transform origin defaults are different to CSS and is less intuitive,
@@ -8800,7 +6105,7 @@ function scrapeMotionValuesFromProps(props, prevProps, visualElement) {
8800
6105
  for (const key in props) {
8801
6106
  if (isMotionValue(props[key]) ||
8802
6107
  isMotionValue(prevProps[key])) {
8803
- const targetKey = transformPropOrder.indexOf(key) !== -1
6108
+ const targetKey = motionDom.transformPropOrder.indexOf(key) !== -1
8804
6109
  ? "attr" + key.charAt(0).toUpperCase() + key.substring(1)
8805
6110
  : key;
8806
6111
  newValues[targetKey] = props[key];
@@ -8820,7 +6125,7 @@ const svgMotionConfig = {
8820
6125
  let hasTransform = !!props.drag;
8821
6126
  if (!hasTransform) {
8822
6127
  for (const key in latestValues) {
8823
- if (transformProps.has(key)) {
6128
+ if (motionDom.transformProps.has(key)) {
8824
6129
  hasTransform = true;
8825
6130
  break;
8826
6131
  }
@@ -8887,8 +6192,8 @@ class SVGVisualElement extends DOMVisualElement {
8887
6192
  return props[key];
8888
6193
  }
8889
6194
  readValueFromInstance(instance, key) {
8890
- if (transformProps.has(key)) {
8891
- const defaultType = getDefaultValueType(key);
6195
+ if (motionDom.transformProps.has(key)) {
6196
+ const defaultType = motionDom.getDefaultValueType(key);
8892
6197
  return defaultType ? defaultType.default || 0 : 0;
8893
6198
  }
8894
6199
  key = !camelCaseAttributes.has(key) ? camelToDash(key) : key;
@@ -8929,7 +6234,6 @@ const createMotionComponent = /*@__PURE__*/ createMotionComponentFactory({
8929
6234
  ...layout,
8930
6235
  }, createDomVisualElement);
8931
6236
 
8932
- exports.AcceleratedAnimation = AcceleratedAnimation;
8933
6237
  exports.FlatTree = FlatTree;
8934
6238
  exports.HTMLVisualElement = HTMLVisualElement;
8935
6239
  exports.LayoutGroupContext = LayoutGroupContext;
@@ -8940,79 +6244,46 @@ exports.PresenceContext = PresenceContext;
8940
6244
  exports.SVGVisualElement = SVGVisualElement;
8941
6245
  exports.SwitchLayoutGroupContext = SwitchLayoutGroupContext;
8942
6246
  exports.VisualElement = VisualElement;
8943
- exports.acceleratedValues = acceleratedValues;
8944
6247
  exports.addDomEvent = addDomEvent;
8945
6248
  exports.addPointerEvent = addPointerEvent;
8946
6249
  exports.addPointerInfo = addPointerInfo;
8947
6250
  exports.addScaleCorrector = addScaleCorrector;
8948
6251
  exports.animateSingleValue = animateSingleValue;
8949
6252
  exports.animateTarget = animateTarget;
8950
- exports.animateValue = animateValue;
8951
6253
  exports.animateVisualElement = animateVisualElement;
8952
6254
  exports.animations = animations;
8953
- exports.anticipate = anticipate;
8954
- exports.backIn = backIn;
8955
- exports.backInOut = backInOut;
8956
- exports.backOut = backOut;
8957
6255
  exports.buildTransform = buildTransform;
8958
6256
  exports.calcLength = calcLength;
8959
6257
  exports.camelToDash = camelToDash;
8960
- exports.circIn = circIn;
8961
- exports.circInOut = circInOut;
8962
- exports.circOut = circOut;
8963
- exports.clamp = clamp;
8964
- exports.color = color;
8965
- exports.complex = complex;
8966
6258
  exports.createBox = createBox;
8967
6259
  exports.createDomVisualElement = createDomVisualElement;
8968
6260
  exports.createMotionComponent = createMotionComponent;
8969
6261
  exports.createMotionComponentFactory = createMotionComponentFactory;
8970
6262
  exports.createRendererMotionComponent = createRendererMotionComponent;
8971
- exports.cubicBezier = cubicBezier;
8972
- exports.defaultOffset = defaultOffset;
8973
6263
  exports.delay = delay;
8974
6264
  exports.distance = distance;
8975
6265
  exports.distance2D = distance2D;
8976
6266
  exports.drag = drag;
8977
- exports.easeIn = easeIn;
8978
- exports.easeInOut = easeInOut;
8979
- exports.easeOut = easeOut;
8980
- exports.easingDefinitionToFunction = easingDefinitionToFunction;
8981
- exports.fillOffset = fillOffset;
8982
6267
  exports.filterProps = filterProps;
8983
- exports.findSpring = findSpring;
8984
6268
  exports.gestureAnimations = gestureAnimations;
8985
6269
  exports.getOptimisedAppearId = getOptimisedAppearId;
8986
6270
  exports.hasReducedMotionListener = hasReducedMotionListener;
8987
- exports.inertia = inertia;
8988
6271
  exports.initPrefersReducedMotion = initPrefersReducedMotion;
8989
- exports.instantAnimationState = instantAnimationState;
8990
- exports.interpolate = interpolate;
8991
6272
  exports.isBrowser = isBrowser;
8992
- exports.isEasingArray = isEasingArray;
8993
6273
  exports.isMotionValue = isMotionValue;
8994
6274
  exports.isSVGElement = isSVGElement;
8995
6275
  exports.isValidMotionProp = isValidMotionProp;
8996
- exports.keyframes = keyframes;
8997
6276
  exports.layout = layout;
8998
6277
  exports.loadExternalIsValidProp = loadExternalIsValidProp;
8999
6278
  exports.loadFeatures = loadFeatures;
9000
6279
  exports.makeUseVisualState = makeUseVisualState;
9001
- exports.mirrorEasing = mirrorEasing;
9002
- exports.mix = mix;
9003
- exports.mixNumber = mixNumber$1;
9004
6280
  exports.motionComponentSymbol = motionComponentSymbol;
9005
6281
  exports.optimizedAppearDataAttribute = optimizedAppearDataAttribute;
9006
6282
  exports.optimizedAppearDataId = optimizedAppearDataId;
9007
- exports.pipe = pipe;
9008
6283
  exports.prefersReducedMotion = prefersReducedMotion;
9009
- exports.px = px;
9010
6284
  exports.resolveMotionValue = resolveMotionValue;
9011
- exports.reverseEasing = reverseEasing;
9012
6285
  exports.rootProjectionNode = rootProjectionNode;
9013
6286
  exports.setTarget = setTarget;
9014
- exports.spring = spring;
9015
- exports.transformProps = transformProps;
9016
6287
  exports.useConstant = useConstant;
9017
6288
  exports.useIsPresent = useIsPresent;
9018
6289
  exports.useIsomorphicLayoutEffect = useIsomorphicLayoutEffect;