motion 12.4.12 → 12.5.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 (83) hide show
  1. package/dist/cjs/debug.js +12 -12
  2. package/dist/cjs/index.js +1353 -1315
  3. package/dist/cjs/mini.js +7 -7
  4. package/dist/cjs/react-client.js +618 -560
  5. package/dist/cjs/react-m.js +20 -19
  6. package/dist/cjs/react-mini.js +1 -1
  7. package/dist/es/framer-motion/dist/es/animation/animate/single-value.mjs +2 -1
  8. package/dist/es/framer-motion/dist/es/animation/animators/BaseAnimation.mjs +2 -1
  9. package/dist/es/framer-motion/dist/es/animation/animators/MainThreadAnimation.mjs +1 -1
  10. package/dist/es/framer-motion/dist/es/animation/animators/drivers/driver-frameloop.mjs +3 -2
  11. package/dist/es/framer-motion/dist/es/animation/animators/waapi/index.mjs +2 -2
  12. package/dist/es/framer-motion/dist/es/animation/generators/utils/velocity.mjs +2 -1
  13. package/dist/es/framer-motion/dist/es/animation/interfaces/motion-value.mjs +2 -2
  14. package/dist/es/framer-motion/dist/es/animation/interfaces/visual-element-target.mjs +1 -1
  15. package/dist/es/framer-motion/dist/es/animation/optimized-appear/start.mjs +4 -4
  16. package/dist/es/framer-motion/dist/es/animation/sequence/utils/edit.mjs +2 -1
  17. package/dist/es/framer-motion/dist/es/components/AnimatePresence/index.mjs +1 -1
  18. package/dist/es/framer-motion/dist/es/components/Reorder/utils/check-reorder.mjs +2 -1
  19. package/dist/es/framer-motion/dist/es/gestures/drag/VisualElementDragControls.mjs +1 -1
  20. package/dist/es/framer-motion/dist/es/gestures/hover.mjs +1 -1
  21. package/dist/es/framer-motion/dist/es/gestures/pan/PanSession.mjs +1 -1
  22. package/dist/es/framer-motion/dist/es/gestures/pan/index.mjs +1 -1
  23. package/dist/es/framer-motion/dist/es/gestures/press.mjs +1 -1
  24. package/dist/es/framer-motion/dist/es/motion/features/layout/MeasureLayout.mjs +3 -2
  25. package/dist/es/framer-motion/dist/es/motion/utils/use-visual-element.mjs +7 -6
  26. package/dist/es/framer-motion/dist/es/projection/node/create-projection-node.mjs +6 -6
  27. package/dist/es/framer-motion/dist/es/projection/shared/stack.mjs +2 -1
  28. package/dist/es/framer-motion/dist/es/render/VisualElement.mjs +6 -5
  29. package/dist/es/framer-motion/dist/es/render/components/create-proxy.mjs +2 -1
  30. package/dist/es/framer-motion/dist/es/render/dom/DOMVisualElement.mjs +1 -1
  31. package/dist/es/framer-motion/dist/es/render/dom/scroll/info.mjs +1 -1
  32. package/dist/es/framer-motion/dist/es/render/dom/scroll/observe.mjs +2 -1
  33. package/dist/es/framer-motion/dist/es/render/dom/scroll/on-scroll-handler.mjs +2 -1
  34. package/dist/es/framer-motion/dist/es/render/dom/scroll/track.mjs +2 -1
  35. package/dist/es/framer-motion/dist/es/render/dom/utils/unit-conversion.mjs +3 -20
  36. package/dist/es/framer-motion/dist/es/render/html/HTMLVisualElement.mjs +2 -3
  37. package/dist/es/framer-motion/dist/es/render/html/utils/parse-transform.mjs +83 -0
  38. package/dist/es/framer-motion/dist/es/render/svg/SVGVisualElement.mjs +2 -1
  39. package/dist/es/framer-motion/dist/es/render/svg/config-motion.mjs +2 -1
  40. package/dist/es/framer-motion/dist/es/render/utils/KeyframesResolver.mjs +2 -1
  41. package/dist/es/framer-motion/dist/es/render/utils/flat-tree.mjs +2 -1
  42. package/dist/es/framer-motion/dist/es/render/utils/motion-values.mjs +4 -3
  43. package/dist/es/framer-motion/dist/es/render/utils/setters.mjs +2 -1
  44. package/dist/es/framer-motion/dist/es/utils/delay.mjs +2 -2
  45. package/dist/es/framer-motion/dist/es/utils/reduced-motion/use-reduced-motion.mjs +2 -1
  46. package/dist/es/framer-motion/dist/es/utils/use-animation-frame.mjs +2 -1
  47. package/dist/es/framer-motion/dist/es/utils/use-force-update.mjs +2 -1
  48. package/dist/es/framer-motion/dist/es/utils/use-instant-transition.mjs +2 -1
  49. package/dist/es/framer-motion/dist/es/value/scroll/use-element-scroll.mjs +2 -1
  50. package/dist/es/framer-motion/dist/es/value/scroll/use-viewport-scroll.mjs +2 -1
  51. package/dist/es/framer-motion/dist/es/value/use-combine-values.mjs +3 -2
  52. package/dist/es/framer-motion/dist/es/value/use-computed.mjs +2 -1
  53. package/dist/es/framer-motion/dist/es/value/use-inverted-scale.mjs +3 -3
  54. package/dist/es/framer-motion/dist/es/value/use-motion-value.mjs +2 -1
  55. package/dist/es/framer-motion/dist/es/value/use-scroll.mjs +4 -4
  56. package/dist/es/framer-motion/dist/es/value/use-spring.mjs +1 -1
  57. package/dist/es/framer-motion/dist/es/value/use-transform.mjs +1 -1
  58. package/dist/es/framer-motion/dist/es/value/use-velocity.mjs +2 -1
  59. package/dist/es/framer-motion/dist/es/value/use-will-change/WillChangeMotionValue.mjs +3 -2
  60. package/dist/es/motion/lib/debug.mjs +1 -1
  61. package/dist/es/motion/lib/index.mjs +3 -4
  62. package/dist/es/motion/lib/react.mjs +19 -20
  63. package/dist/es/{framer-motion → motion-dom}/dist/es/frameloop/batcher.mjs +2 -1
  64. package/dist/es/{framer-motion → motion-dom}/dist/es/frameloop/frame.mjs +1 -1
  65. package/dist/es/motion-dom/dist/es/frameloop/microtask.mjs +6 -0
  66. package/dist/es/{framer-motion → motion-dom}/dist/es/frameloop/sync-time.mjs +2 -1
  67. package/dist/es/motion-dom/dist/es/utils/supports/scroll-timeline.mjs +1 -1
  68. package/dist/es/{framer-motion → motion-dom}/dist/es/value/index.mjs +6 -11
  69. package/dist/motion.dev.js +1353 -1315
  70. package/dist/motion.js +1 -1
  71. package/package.json +3 -3
  72. package/dist/es/framer-motion/dist/es/frameloop/index-legacy.mjs +0 -20
  73. package/dist/es/framer-motion/dist/es/frameloop/microtask.mjs +0 -5
  74. package/dist/es/{framer-motion → motion-dom}/dist/es/frameloop/order.mjs +0 -0
  75. package/dist/es/{framer-motion → motion-dom}/dist/es/frameloop/render-step.mjs +0 -0
  76. package/dist/es/{framer-motion → motion-dom}/dist/es/stats/animation-count.mjs +0 -0
  77. package/dist/es/{framer-motion → motion-dom}/dist/es/stats/buffer.mjs +0 -0
  78. package/dist/es/{framer-motion → motion-dom}/dist/es/stats/index.mjs +1 -1
  79. /package/dist/es/{framer-motion/dist/es/utils → motion-utils/dist/es}/array.mjs +0 -0
  80. /package/dist/es/{framer-motion/dist/es/utils/GlobalConfig.mjs → motion-utils/dist/es/global-config.mjs} +0 -0
  81. /package/dist/es/{framer-motion/dist/es/utils → motion-utils/dist/es}/subscription-manager.mjs +0 -0
  82. /package/dist/es/{framer-motion/dist/es/utils → motion-utils/dist/es}/velocity-per-second.mjs +0 -0
  83. /package/dist/es/{framer-motion/dist/es/utils → motion-utils/dist/es}/warn-once.mjs +0 -0
@@ -51,6 +51,16 @@ function resolveVariant(visualElement, definition, custom) {
51
51
  return resolveVariantFromProps(props, definition, custom !== undefined ? custom : props.custom, visualElement);
52
52
  }
53
53
 
54
+ function addUniqueItem(arr, item) {
55
+ if (arr.indexOf(item) === -1)
56
+ arr.push(item);
57
+ }
58
+ function removeItem(arr, item) {
59
+ const index = arr.indexOf(item);
60
+ if (index > -1)
61
+ arr.splice(index, 1);
62
+ }
63
+
54
64
  /*#__NO_SIDE_EFFECTS__*/
55
65
  const noop = (any) => any;
56
66
 
@@ -69,6 +79,11 @@ if (process.env.NODE_ENV !== "production") {
69
79
  };
70
80
  }
71
81
 
82
+ const MotionGlobalConfig = {
83
+ skipAnimations: false,
84
+ useManualTiming: false,
85
+ };
86
+
72
87
  /*#__NO_SIDE_EFFECTS__*/
73
88
  function memo(callback) {
74
89
  let result;
@@ -97,6 +112,43 @@ const progress = (from, to, value) => {
97
112
  return toFromDifference === 0 ? 1 : (value - from) / toFromDifference;
98
113
  };
99
114
 
115
+ class SubscriptionManager {
116
+ constructor() {
117
+ this.subscriptions = [];
118
+ }
119
+ add(handler) {
120
+ addUniqueItem(this.subscriptions, handler);
121
+ return () => removeItem(this.subscriptions, handler);
122
+ }
123
+ notify(a, b, c) {
124
+ const numSubscriptions = this.subscriptions.length;
125
+ if (!numSubscriptions)
126
+ return;
127
+ if (numSubscriptions === 1) {
128
+ /**
129
+ * If there's only a single handler we can just call it without invoking a loop.
130
+ */
131
+ this.subscriptions[0](a, b, c);
132
+ }
133
+ else {
134
+ for (let i = 0; i < numSubscriptions; i++) {
135
+ /**
136
+ * Check whether the handler exists before firing as it's possible
137
+ * the subscriptions were modified during this loop running.
138
+ */
139
+ const handler = this.subscriptions[i];
140
+ handler && handler(a, b, c);
141
+ }
142
+ }
143
+ }
144
+ getSize() {
145
+ return this.subscriptions.length;
146
+ }
147
+ clear() {
148
+ this.subscriptions.length = 0;
149
+ }
150
+ }
151
+
100
152
  /**
101
153
  * Converts seconds to milliseconds
102
154
  *
@@ -108,7 +160,27 @@ const secondsToMilliseconds = (seconds) => seconds * 1000;
108
160
  /*#__NO_SIDE_EFFECTS__*/
109
161
  const millisecondsToSeconds = (milliseconds) => milliseconds / 1000;
110
162
 
111
- const supportsScrollTimeline = memo(() => window.ScrollTimeline !== undefined);
163
+ /*
164
+ Convert velocity into velocity per second
165
+
166
+ @param [number]: Unit per frame
167
+ @param [number]: Frame duration in ms
168
+ */
169
+ function velocityPerSecond(velocity, frameDuration) {
170
+ return frameDuration ? velocity * (1000 / frameDuration) : 0;
171
+ }
172
+
173
+ const warned = new Set();
174
+ function warnOnce(condition, message, element) {
175
+ if (condition || warned.has(message))
176
+ return;
177
+ console.warn(message);
178
+ if (element)
179
+ console.warn(element);
180
+ warned.add(message);
181
+ }
182
+
183
+ const supportsScrollTimeline = /* @__PURE__ */ memo(() => window.ScrollTimeline !== undefined);
112
184
 
113
185
  class BaseGroupPlaybackControls {
114
186
  constructor(animations) {
@@ -309,454 +381,107 @@ function mapEasingToNativeEasing(easing, duration) {
309
381
  }
310
382
  }
311
383
 
312
- const isDragging = {
313
- x: false,
314
- y: false,
384
+ const stepsOrder = [
385
+ "read", // Read
386
+ "resolveKeyframes", // Write/Read/Write/Read
387
+ "update", // Compute
388
+ "preRender", // Compute
389
+ "render", // Write
390
+ "postRender", // Compute
391
+ ];
392
+
393
+ const statsBuffer = {
394
+ value: null,
395
+ addProjectionMetrics: null,
315
396
  };
316
- function isDragActive() {
317
- return isDragging.x || isDragging.y;
318
- }
319
397
 
320
- function resolveElements(elementOrSelector, scope, selectorCache) {
321
- var _a;
322
- if (elementOrSelector instanceof EventTarget) {
323
- return [elementOrSelector];
324
- }
325
- else if (typeof elementOrSelector === "string") {
326
- let root = document;
327
- if (scope) {
328
- // TODO: Refactor to utils package
329
- // invariant(
330
- // Boolean(scope.current),
331
- // "Scope provided, but no element detected."
332
- // )
333
- root = scope.current;
398
+ function createRenderStep(runNextFrame, stepName) {
399
+ /**
400
+ * We create and reuse two queues, one to queue jobs for the current frame
401
+ * and one for the next. We reuse to avoid triggering GC after x frames.
402
+ */
403
+ let thisFrame = new Set();
404
+ let nextFrame = new Set();
405
+ /**
406
+ * Track whether we're currently processing jobs in this step. This way
407
+ * we can decide whether to schedule new jobs for this frame or next.
408
+ */
409
+ let isProcessing = false;
410
+ let flushNextFrame = false;
411
+ /**
412
+ * A set of processes which were marked keepAlive when scheduled.
413
+ */
414
+ const toKeepAlive = new WeakSet();
415
+ let latestFrameData = {
416
+ delta: 0.0,
417
+ timestamp: 0.0,
418
+ isProcessing: false,
419
+ };
420
+ let numCalls = 0;
421
+ function triggerCallback(callback) {
422
+ if (toKeepAlive.has(callback)) {
423
+ step.schedule(callback);
424
+ runNextFrame();
334
425
  }
335
- const elements = (_a = selectorCache === null || selectorCache === void 0 ? void 0 : selectorCache[elementOrSelector]) !== null && _a !== void 0 ? _a : root.querySelectorAll(elementOrSelector);
336
- return elements ? Array.from(elements) : [];
426
+ numCalls++;
427
+ callback(latestFrameData);
337
428
  }
338
- return Array.from(elementOrSelector);
339
- }
340
-
341
- function setupGesture(elementOrSelector, options) {
342
- const elements = resolveElements(elementOrSelector);
343
- const gestureAbortController = new AbortController();
344
- const eventOptions = {
345
- passive: true,
346
- ...options,
347
- signal: gestureAbortController.signal,
348
- };
349
- const cancel = () => gestureAbortController.abort();
350
- return [elements, eventOptions, cancel];
351
- }
352
-
353
- function isValidHover(event) {
354
- return !(event.pointerType === "touch" || isDragActive());
355
- }
356
- /**
357
- * Create a hover gesture. hover() is different to .addEventListener("pointerenter")
358
- * in that it has an easier syntax, filters out polyfilled touch events, interoperates
359
- * with drag gestures, and automatically removes the "pointerennd" event listener when the hover ends.
360
- *
361
- * @public
362
- */
363
- function hover(elementOrSelector, onHoverStart, options = {}) {
364
- const [elements, eventOptions, cancel] = setupGesture(elementOrSelector, options);
365
- const onPointerEnter = (enterEvent) => {
366
- if (!isValidHover(enterEvent))
367
- return;
368
- const { target } = enterEvent;
369
- const onHoverEnd = onHoverStart(target, enterEvent);
370
- if (typeof onHoverEnd !== "function" || !target)
371
- return;
372
- const onPointerLeave = (leaveEvent) => {
373
- if (!isValidHover(leaveEvent))
429
+ const step = {
430
+ /**
431
+ * Schedule a process to run on the next frame.
432
+ */
433
+ schedule: (callback, keepAlive = false, immediate = false) => {
434
+ const addToCurrentFrame = immediate && isProcessing;
435
+ const queue = addToCurrentFrame ? thisFrame : nextFrame;
436
+ if (keepAlive)
437
+ toKeepAlive.add(callback);
438
+ if (!queue.has(callback))
439
+ queue.add(callback);
440
+ return callback;
441
+ },
442
+ /**
443
+ * Cancel the provided callback from running on the next frame.
444
+ */
445
+ cancel: (callback) => {
446
+ nextFrame.delete(callback);
447
+ toKeepAlive.delete(callback);
448
+ },
449
+ /**
450
+ * Execute all schedule callbacks.
451
+ */
452
+ process: (frameData) => {
453
+ latestFrameData = frameData;
454
+ /**
455
+ * If we're already processing we've probably been triggered by a flushSync
456
+ * inside an existing process. Instead of executing, mark flushNextFrame
457
+ * as true and ensure we flush the following frame at the end of this one.
458
+ */
459
+ if (isProcessing) {
460
+ flushNextFrame = true;
374
461
  return;
375
- onHoverEnd(leaveEvent);
376
- target.removeEventListener("pointerleave", onPointerLeave);
377
- };
378
- target.addEventListener("pointerleave", onPointerLeave, eventOptions);
462
+ }
463
+ isProcessing = true;
464
+ [thisFrame, nextFrame] = [nextFrame, thisFrame];
465
+ // Execute this frame
466
+ thisFrame.forEach(triggerCallback);
467
+ /**
468
+ * If we're recording stats then
469
+ */
470
+ if (stepName && statsBuffer.value) {
471
+ statsBuffer.value.frameloop[stepName].push(numCalls);
472
+ }
473
+ numCalls = 0;
474
+ // Clear the frame so no callbacks remain. This is to avoid
475
+ // memory leaks should this render step not run for a while.
476
+ thisFrame.clear();
477
+ isProcessing = false;
478
+ if (flushNextFrame) {
479
+ flushNextFrame = false;
480
+ step.process(frameData);
481
+ }
482
+ },
379
483
  };
380
- elements.forEach((element) => {
381
- element.addEventListener("pointerenter", onPointerEnter, eventOptions);
382
- });
383
- return cancel;
384
- }
385
-
386
- function capturePointer(event, action) {
387
- const actionName = `${action}PointerCapture`;
388
- if (event.target instanceof Element &&
389
- actionName in event.target &&
390
- event.pointerId !== undefined) {
391
- try {
392
- event.target[actionName](event.pointerId);
393
- }
394
- catch (e) { }
395
- }
396
- }
397
-
398
- /**
399
- * Recursively traverse up the tree to check whether the provided child node
400
- * is the parent or a descendant of it.
401
- *
402
- * @param parent - Element to find
403
- * @param child - Element to test against parent
404
- */
405
- const isNodeOrChild = (parent, child) => {
406
- if (!child) {
407
- return false;
408
- }
409
- else if (parent === child) {
410
- return true;
411
- }
412
- else {
413
- return isNodeOrChild(parent, child.parentElement);
414
- }
415
- };
416
-
417
- const isPrimaryPointer = (event) => {
418
- if (event.pointerType === "mouse") {
419
- return typeof event.button !== "number" || event.button <= 0;
420
- }
421
- else {
422
- /**
423
- * isPrimary is true for all mice buttons, whereas every touch point
424
- * is regarded as its own input. So subsequent concurrent touch points
425
- * will be false.
426
- *
427
- * Specifically match against false here as incomplete versions of
428
- * PointerEvents in very old browser might have it set as undefined.
429
- */
430
- return event.isPrimary !== false;
431
- }
432
- };
433
-
434
- const focusableElements = new Set([
435
- "BUTTON",
436
- "INPUT",
437
- "SELECT",
438
- "TEXTAREA",
439
- "A",
440
- ]);
441
- function isElementKeyboardAccessible(element) {
442
- return (focusableElements.has(element.tagName) ||
443
- element.tabIndex !== -1);
444
- }
445
-
446
- const isPressing = new WeakSet();
447
-
448
- /**
449
- * Filter out events that are not "Enter" keys.
450
- */
451
- function filterEvents(callback) {
452
- return (event) => {
453
- if (event.key !== "Enter")
454
- return;
455
- callback(event);
456
- };
457
- }
458
- function firePointerEvent(target, type) {
459
- target.dispatchEvent(new PointerEvent("pointer" + type, { isPrimary: true, bubbles: true }));
460
- }
461
- const enableKeyboardPress = (focusEvent, eventOptions) => {
462
- const element = focusEvent.currentTarget;
463
- if (!element)
464
- return;
465
- const handleKeydown = filterEvents(() => {
466
- if (isPressing.has(element))
467
- return;
468
- firePointerEvent(element, "down");
469
- const handleKeyup = filterEvents(() => {
470
- firePointerEvent(element, "up");
471
- });
472
- const handleBlur = () => firePointerEvent(element, "cancel");
473
- element.addEventListener("keyup", handleKeyup, eventOptions);
474
- element.addEventListener("blur", handleBlur, eventOptions);
475
- });
476
- element.addEventListener("keydown", handleKeydown, eventOptions);
477
- /**
478
- * Add an event listener that fires on blur to remove the keydown events.
479
- */
480
- element.addEventListener("blur", () => element.removeEventListener("keydown", handleKeydown), eventOptions);
481
- };
482
-
483
- /**
484
- * Filter out events that are not primary pointer events, or are triggering
485
- * while a Motion gesture is active.
486
- */
487
- function isValidPressEvent(event) {
488
- return isPrimaryPointer(event) && !isDragActive();
489
- }
490
- /**
491
- * Create a press gesture.
492
- *
493
- * Press is different to `"pointerdown"`, `"pointerup"` in that it
494
- * automatically filters out secondary pointer events like right
495
- * click and multitouch.
496
- *
497
- * It also adds accessibility support for keyboards, where
498
- * an element with a press gesture will receive focus and
499
- * trigger on Enter `"keydown"` and `"keyup"` events.
500
- *
501
- * This is different to a browser's `"click"` event, which does
502
- * respond to keyboards but only for the `"click"` itself, rather
503
- * than the press start and end/cancel. The element also needs
504
- * to be focusable for this to work, whereas a press gesture will
505
- * make an element focusable by default.
506
- *
507
- * @public
508
- */
509
- function press(targetOrSelector, onPressStart, options = {}) {
510
- const [targets, eventOptions, cancelEvents] = setupGesture(targetOrSelector, options);
511
- const startPress = (startEvent) => {
512
- const target = startEvent.currentTarget;
513
- if (!target || !isValidPressEvent(startEvent) || isPressing.has(target))
514
- return;
515
- isPressing.add(target);
516
- capturePointer(startEvent, "set");
517
- const onPressEnd = onPressStart(target, startEvent);
518
- const onPointerEnd = (endEvent, success) => {
519
- target.removeEventListener("pointerup", onPointerUp);
520
- target.removeEventListener("pointercancel", onPointerCancel);
521
- capturePointer(endEvent, "release");
522
- if (!isValidPressEvent(endEvent) || !isPressing.has(target)) {
523
- return;
524
- }
525
- isPressing.delete(target);
526
- if (typeof onPressEnd === "function") {
527
- onPressEnd(endEvent, { success });
528
- }
529
- };
530
- const onPointerUp = (upEvent) => {
531
- const isOutside = !upEvent.isTrusted
532
- ? false
533
- : checkOutside(upEvent, target instanceof Element
534
- ? target.getBoundingClientRect()
535
- : {
536
- left: 0,
537
- top: 0,
538
- right: window.innerWidth,
539
- bottom: window.innerHeight,
540
- });
541
- if (isOutside) {
542
- onPointerEnd(upEvent, false);
543
- }
544
- else {
545
- onPointerEnd(upEvent, !(target instanceof Element) ||
546
- isNodeOrChild(target, upEvent.target));
547
- }
548
- };
549
- const onPointerCancel = (cancelEvent) => {
550
- onPointerEnd(cancelEvent, false);
551
- };
552
- target.addEventListener("pointerup", onPointerUp, eventOptions);
553
- target.addEventListener("pointercancel", onPointerCancel, eventOptions);
554
- target.addEventListener("lostpointercapture", onPointerCancel, eventOptions);
555
- };
556
- targets.forEach((target) => {
557
- target = options.useGlobalTarget ? window : target;
558
- let canAddKeyboardAccessibility = false;
559
- if (target instanceof HTMLElement) {
560
- canAddKeyboardAccessibility = true;
561
- if (!isElementKeyboardAccessible(target) &&
562
- target.getAttribute("tabindex") === null) {
563
- target.tabIndex = 0;
564
- }
565
- }
566
- target.addEventListener("pointerdown", startPress, eventOptions);
567
- if (canAddKeyboardAccessibility) {
568
- target.addEventListener("focus", (event) => enableKeyboardPress(event, eventOptions), eventOptions);
569
- }
570
- });
571
- return cancelEvents;
572
- }
573
- function checkOutside(event, rect) {
574
- return (event.clientX < rect.left ||
575
- event.clientX > rect.right ||
576
- event.clientY < rect.top ||
577
- event.clientY > rect.bottom);
578
- }
579
-
580
- function setDragLock(axis) {
581
- if (axis === "x" || axis === "y") {
582
- if (isDragging[axis]) {
583
- return null;
584
- }
585
- else {
586
- isDragging[axis] = true;
587
- return () => {
588
- isDragging[axis] = false;
589
- };
590
- }
591
- }
592
- else {
593
- if (isDragging.x || isDragging.y) {
594
- return null;
595
- }
596
- else {
597
- isDragging.x = isDragging.y = true;
598
- return () => {
599
- isDragging.x = isDragging.y = false;
600
- };
601
- }
602
- }
603
- }
604
-
605
- /**
606
- * Generate a list of every possible transform key.
607
- */
608
- const transformPropOrder = [
609
- "transformPerspective",
610
- "x",
611
- "y",
612
- "z",
613
- "translateX",
614
- "translateY",
615
- "translateZ",
616
- "scale",
617
- "scaleX",
618
- "scaleY",
619
- "rotate",
620
- "rotateX",
621
- "rotateY",
622
- "rotateZ",
623
- "skew",
624
- "skewX",
625
- "skewY",
626
- ];
627
- /**
628
- * A quick lookup for transform props.
629
- */
630
- const transformProps = new Set(transformPropOrder);
631
-
632
- const positionalKeys = new Set([
633
- "width",
634
- "height",
635
- "top",
636
- "left",
637
- "right",
638
- "bottom",
639
- ...transformPropOrder,
640
- ]);
641
-
642
- const isKeyframesTarget = (v) => {
643
- return Array.isArray(v);
644
- };
645
-
646
- const isCustomValue = (v) => {
647
- return Boolean(v && typeof v === "object" && v.mix && v.toValue);
648
- };
649
- const resolveFinalValueInKeyframes = (v) => {
650
- // TODO maybe throw if v.length - 1 is placeholder token?
651
- return isKeyframesTarget(v) ? v[v.length - 1] || 0 : v;
652
- };
653
-
654
- const MotionGlobalConfig = {
655
- skipAnimations: false,
656
- useManualTiming: false,
657
- };
658
-
659
- const stepsOrder = [
660
- "read", // Read
661
- "resolveKeyframes", // Write/Read/Write/Read
662
- "update", // Compute
663
- "preRender", // Compute
664
- "render", // Write
665
- "postRender", // Compute
666
- ];
667
-
668
- const statsBuffer = {
669
- value: null,
670
- addProjectionMetrics: null,
671
- };
672
-
673
- function createRenderStep(runNextFrame, stepName) {
674
- /**
675
- * We create and reuse two queues, one to queue jobs for the current frame
676
- * and one for the next. We reuse to avoid triggering GC after x frames.
677
- */
678
- let thisFrame = new Set();
679
- let nextFrame = new Set();
680
- /**
681
- * Track whether we're currently processing jobs in this step. This way
682
- * we can decide whether to schedule new jobs for this frame or next.
683
- */
684
- let isProcessing = false;
685
- let flushNextFrame = false;
686
- /**
687
- * A set of processes which were marked keepAlive when scheduled.
688
- */
689
- const toKeepAlive = new WeakSet();
690
- let latestFrameData = {
691
- delta: 0.0,
692
- timestamp: 0.0,
693
- isProcessing: false,
694
- };
695
- let numCalls = 0;
696
- function triggerCallback(callback) {
697
- if (toKeepAlive.has(callback)) {
698
- step.schedule(callback);
699
- runNextFrame();
700
- }
701
- numCalls++;
702
- callback(latestFrameData);
703
- }
704
- const step = {
705
- /**
706
- * Schedule a process to run on the next frame.
707
- */
708
- schedule: (callback, keepAlive = false, immediate = false) => {
709
- const addToCurrentFrame = immediate && isProcessing;
710
- const queue = addToCurrentFrame ? thisFrame : nextFrame;
711
- if (keepAlive)
712
- toKeepAlive.add(callback);
713
- if (!queue.has(callback))
714
- queue.add(callback);
715
- return callback;
716
- },
717
- /**
718
- * Cancel the provided callback from running on the next frame.
719
- */
720
- cancel: (callback) => {
721
- nextFrame.delete(callback);
722
- toKeepAlive.delete(callback);
723
- },
724
- /**
725
- * Execute all schedule callbacks.
726
- */
727
- process: (frameData) => {
728
- latestFrameData = frameData;
729
- /**
730
- * If we're already processing we've probably been triggered by a flushSync
731
- * inside an existing process. Instead of executing, mark flushNextFrame
732
- * as true and ensure we flush the following frame at the end of this one.
733
- */
734
- if (isProcessing) {
735
- flushNextFrame = true;
736
- return;
737
- }
738
- isProcessing = true;
739
- [thisFrame, nextFrame] = [nextFrame, thisFrame];
740
- // Execute this frame
741
- thisFrame.forEach(triggerCallback);
742
- /**
743
- * If we're recording stats then
744
- */
745
- if (stepName && statsBuffer.value) {
746
- statsBuffer.value.frameloop[stepName].push(numCalls);
747
- }
748
- numCalls = 0;
749
- // Clear the frame so no callbacks remain. This is to avoid
750
- // memory leaks should this render step not run for a while.
751
- thisFrame.clear();
752
- isProcessing = false;
753
- if (flushNextFrame) {
754
- flushNextFrame = false;
755
- step.process(frameData);
756
- }
757
- },
758
- };
759
- return step;
484
+ return step;
760
485
  }
761
486
 
762
487
  const maxElapsed = 40;
@@ -821,100 +546,329 @@ function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
821
546
  return { schedule, cancel, state, steps };
822
547
  }
823
548
 
824
- const { schedule: frame, cancel: cancelFrame, state: frameData, steps: frameSteps, } = createRenderBatcher(typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : noop, true);
549
+ const { schedule: frame, cancel: cancelFrame, state: frameData, steps: frameSteps, } = /* @__PURE__ */ createRenderBatcher(typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : noop, true);
550
+
551
+ const { schedule: microtask, cancel: cancelMicrotask } =
552
+ /* @__PURE__ */ createRenderBatcher(queueMicrotask, false);
553
+
554
+ let now;
555
+ function clearTime() {
556
+ now = undefined;
557
+ }
558
+ /**
559
+ * An eventloop-synchronous alternative to performance.now().
560
+ *
561
+ * Ensures that time measurements remain consistent within a synchronous context.
562
+ * Usually calling performance.now() twice within the same synchronous context
563
+ * will return different values which isn't useful for animations when we're usually
564
+ * trying to sync animations to the same frame.
565
+ */
566
+ const time = {
567
+ now: () => {
568
+ if (now === undefined) {
569
+ time.set(frameData.isProcessing || MotionGlobalConfig.useManualTiming
570
+ ? frameData.timestamp
571
+ : performance.now());
572
+ }
573
+ return now;
574
+ },
575
+ set: (newTime) => {
576
+ now = newTime;
577
+ queueMicrotask(clearTime);
578
+ },
579
+ };
580
+
581
+ const isDragging = {
582
+ x: false,
583
+ y: false,
584
+ };
585
+ function isDragActive() {
586
+ return isDragging.x || isDragging.y;
587
+ }
588
+
589
+ function setDragLock(axis) {
590
+ if (axis === "x" || axis === "y") {
591
+ if (isDragging[axis]) {
592
+ return null;
593
+ }
594
+ else {
595
+ isDragging[axis] = true;
596
+ return () => {
597
+ isDragging[axis] = false;
598
+ };
599
+ }
600
+ }
601
+ else {
602
+ if (isDragging.x || isDragging.y) {
603
+ return null;
604
+ }
605
+ else {
606
+ isDragging.x = isDragging.y = true;
607
+ return () => {
608
+ isDragging.x = isDragging.y = false;
609
+ };
610
+ }
611
+ }
612
+ }
613
+
614
+ function resolveElements(elementOrSelector, scope, selectorCache) {
615
+ var _a;
616
+ if (elementOrSelector instanceof EventTarget) {
617
+ return [elementOrSelector];
618
+ }
619
+ else if (typeof elementOrSelector === "string") {
620
+ let root = document;
621
+ if (scope) {
622
+ // TODO: Refactor to utils package
623
+ // invariant(
624
+ // Boolean(scope.current),
625
+ // "Scope provided, but no element detected."
626
+ // )
627
+ root = scope.current;
628
+ }
629
+ const elements = (_a = selectorCache === null || selectorCache === void 0 ? void 0 : selectorCache[elementOrSelector]) !== null && _a !== void 0 ? _a : root.querySelectorAll(elementOrSelector);
630
+ return elements ? Array.from(elements) : [];
631
+ }
632
+ return Array.from(elementOrSelector);
633
+ }
634
+
635
+ function setupGesture(elementOrSelector, options) {
636
+ const elements = resolveElements(elementOrSelector);
637
+ const gestureAbortController = new AbortController();
638
+ const eventOptions = {
639
+ passive: true,
640
+ ...options,
641
+ signal: gestureAbortController.signal,
642
+ };
643
+ const cancel = () => gestureAbortController.abort();
644
+ return [elements, eventOptions, cancel];
645
+ }
646
+
647
+ function isValidHover(event) {
648
+ return !(event.pointerType === "touch" || isDragActive());
649
+ }
650
+ /**
651
+ * Create a hover gesture. hover() is different to .addEventListener("pointerenter")
652
+ * in that it has an easier syntax, filters out polyfilled touch events, interoperates
653
+ * with drag gestures, and automatically removes the "pointerennd" event listener when the hover ends.
654
+ *
655
+ * @public
656
+ */
657
+ function hover(elementOrSelector, onHoverStart, options = {}) {
658
+ const [elements, eventOptions, cancel] = setupGesture(elementOrSelector, options);
659
+ const onPointerEnter = (enterEvent) => {
660
+ if (!isValidHover(enterEvent))
661
+ return;
662
+ const { target } = enterEvent;
663
+ const onHoverEnd = onHoverStart(target, enterEvent);
664
+ if (typeof onHoverEnd !== "function" || !target)
665
+ return;
666
+ const onPointerLeave = (leaveEvent) => {
667
+ if (!isValidHover(leaveEvent))
668
+ return;
669
+ onHoverEnd(leaveEvent);
670
+ target.removeEventListener("pointerleave", onPointerLeave);
671
+ };
672
+ target.addEventListener("pointerleave", onPointerLeave, eventOptions);
673
+ };
674
+ elements.forEach((element) => {
675
+ element.addEventListener("pointerenter", onPointerEnter, eventOptions);
676
+ });
677
+ return cancel;
678
+ }
679
+
680
+ function capturePointer(event, action) {
681
+ const actionName = `${action}PointerCapture`;
682
+ if (event.target instanceof Element &&
683
+ actionName in event.target &&
684
+ event.pointerId !== undefined) {
685
+ try {
686
+ event.target[actionName](event.pointerId);
687
+ }
688
+ catch (e) { }
689
+ }
690
+ }
691
+
692
+ /**
693
+ * Recursively traverse up the tree to check whether the provided child node
694
+ * is the parent or a descendant of it.
695
+ *
696
+ * @param parent - Element to find
697
+ * @param child - Element to test against parent
698
+ */
699
+ const isNodeOrChild = (parent, child) => {
700
+ if (!child) {
701
+ return false;
702
+ }
703
+ else if (parent === child) {
704
+ return true;
705
+ }
706
+ else {
707
+ return isNodeOrChild(parent, child.parentElement);
708
+ }
709
+ };
710
+
711
+ const isPrimaryPointer = (event) => {
712
+ if (event.pointerType === "mouse") {
713
+ return typeof event.button !== "number" || event.button <= 0;
714
+ }
715
+ else {
716
+ /**
717
+ * isPrimary is true for all mice buttons, whereas every touch point
718
+ * is regarded as its own input. So subsequent concurrent touch points
719
+ * will be false.
720
+ *
721
+ * Specifically match against false here as incomplete versions of
722
+ * PointerEvents in very old browser might have it set as undefined.
723
+ */
724
+ return event.isPrimary !== false;
725
+ }
726
+ };
727
+
728
+ const focusableElements = new Set([
729
+ "BUTTON",
730
+ "INPUT",
731
+ "SELECT",
732
+ "TEXTAREA",
733
+ "A",
734
+ ]);
735
+ function isElementKeyboardAccessible(element) {
736
+ return (focusableElements.has(element.tagName) ||
737
+ element.tabIndex !== -1);
738
+ }
739
+
740
+ const isPressing = new WeakSet();
741
+
742
+ /**
743
+ * Filter out events that are not "Enter" keys.
744
+ */
745
+ function filterEvents(callback) {
746
+ return (event) => {
747
+ if (event.key !== "Enter")
748
+ return;
749
+ callback(event);
750
+ };
751
+ }
752
+ function firePointerEvent(target, type) {
753
+ target.dispatchEvent(new PointerEvent("pointer" + type, { isPrimary: true, bubbles: true }));
754
+ }
755
+ const enableKeyboardPress = (focusEvent, eventOptions) => {
756
+ const element = focusEvent.currentTarget;
757
+ if (!element)
758
+ return;
759
+ const handleKeydown = filterEvents(() => {
760
+ if (isPressing.has(element))
761
+ return;
762
+ firePointerEvent(element, "down");
763
+ const handleKeyup = filterEvents(() => {
764
+ firePointerEvent(element, "up");
765
+ });
766
+ const handleBlur = () => firePointerEvent(element, "cancel");
767
+ element.addEventListener("keyup", handleKeyup, eventOptions);
768
+ element.addEventListener("blur", handleBlur, eventOptions);
769
+ });
770
+ element.addEventListener("keydown", handleKeydown, eventOptions);
771
+ /**
772
+ * Add an event listener that fires on blur to remove the keydown events.
773
+ */
774
+ element.addEventListener("blur", () => element.removeEventListener("keydown", handleKeydown), eventOptions);
775
+ };
825
776
 
826
- let now;
827
- function clearTime() {
828
- now = undefined;
777
+ /**
778
+ * Filter out events that are not primary pointer events, or are triggering
779
+ * while a Motion gesture is active.
780
+ */
781
+ function isValidPressEvent(event) {
782
+ return isPrimaryPointer(event) && !isDragActive();
829
783
  }
830
784
  /**
831
- * An eventloop-synchronous alternative to performance.now().
785
+ * Create a press gesture.
832
786
  *
833
- * Ensures that time measurements remain consistent within a synchronous context.
834
- * Usually calling performance.now() twice within the same synchronous context
835
- * will return different values which isn't useful for animations when we're usually
836
- * trying to sync animations to the same frame.
787
+ * Press is different to `"pointerdown"`, `"pointerup"` in that it
788
+ * automatically filters out secondary pointer events like right
789
+ * click and multitouch.
790
+ *
791
+ * It also adds accessibility support for keyboards, where
792
+ * an element with a press gesture will receive focus and
793
+ * trigger on Enter `"keydown"` and `"keyup"` events.
794
+ *
795
+ * This is different to a browser's `"click"` event, which does
796
+ * respond to keyboards but only for the `"click"` itself, rather
797
+ * than the press start and end/cancel. The element also needs
798
+ * to be focusable for this to work, whereas a press gesture will
799
+ * make an element focusable by default.
800
+ *
801
+ * @public
837
802
  */
838
- const time = {
839
- now: () => {
840
- if (now === undefined) {
841
- time.set(frameData.isProcessing || MotionGlobalConfig.useManualTiming
842
- ? frameData.timestamp
843
- : performance.now());
844
- }
845
- return now;
846
- },
847
- set: (newTime) => {
848
- now = newTime;
849
- queueMicrotask(clearTime);
850
- },
851
- };
852
-
853
- function addUniqueItem(arr, item) {
854
- if (arr.indexOf(item) === -1)
855
- arr.push(item);
856
- }
857
- function removeItem(arr, item) {
858
- const index = arr.indexOf(item);
859
- if (index > -1)
860
- arr.splice(index, 1);
861
- }
862
-
863
- class SubscriptionManager {
864
- constructor() {
865
- this.subscriptions = [];
866
- }
867
- add(handler) {
868
- addUniqueItem(this.subscriptions, handler);
869
- return () => removeItem(this.subscriptions, handler);
870
- }
871
- notify(a, b, c) {
872
- const numSubscriptions = this.subscriptions.length;
873
- if (!numSubscriptions)
803
+ function press(targetOrSelector, onPressStart, options = {}) {
804
+ const [targets, eventOptions, cancelEvents] = setupGesture(targetOrSelector, options);
805
+ const startPress = (startEvent) => {
806
+ const target = startEvent.currentTarget;
807
+ if (!target || !isValidPressEvent(startEvent) || isPressing.has(target))
874
808
  return;
875
- if (numSubscriptions === 1) {
876
- /**
877
- * If there's only a single handler we can just call it without invoking a loop.
878
- */
879
- this.subscriptions[0](a, b, c);
880
- }
881
- else {
882
- for (let i = 0; i < numSubscriptions; i++) {
883
- /**
884
- * Check whether the handler exists before firing as it's possible
885
- * the subscriptions were modified during this loop running.
886
- */
887
- const handler = this.subscriptions[i];
888
- handler && handler(a, b, c);
809
+ isPressing.add(target);
810
+ capturePointer(startEvent, "set");
811
+ const onPressEnd = onPressStart(target, startEvent);
812
+ const onPointerEnd = (endEvent, success) => {
813
+ target.removeEventListener("pointerup", onPointerUp);
814
+ target.removeEventListener("pointercancel", onPointerCancel);
815
+ capturePointer(endEvent, "release");
816
+ if (!isValidPressEvent(endEvent) || !isPressing.has(target)) {
817
+ return;
818
+ }
819
+ isPressing.delete(target);
820
+ if (typeof onPressEnd === "function") {
821
+ onPressEnd(endEvent, { success });
822
+ }
823
+ };
824
+ const onPointerUp = (upEvent) => {
825
+ const isOutside = !upEvent.isTrusted
826
+ ? false
827
+ : checkOutside(upEvent, target instanceof Element
828
+ ? target.getBoundingClientRect()
829
+ : {
830
+ left: 0,
831
+ top: 0,
832
+ right: window.innerWidth,
833
+ bottom: window.innerHeight,
834
+ });
835
+ if (isOutside) {
836
+ onPointerEnd(upEvent, false);
837
+ }
838
+ else {
839
+ onPointerEnd(upEvent, !(target instanceof Element) ||
840
+ isNodeOrChild(target, upEvent.target));
841
+ }
842
+ };
843
+ const onPointerCancel = (cancelEvent) => {
844
+ onPointerEnd(cancelEvent, false);
845
+ };
846
+ target.addEventListener("pointerup", onPointerUp, eventOptions);
847
+ target.addEventListener("pointercancel", onPointerCancel, eventOptions);
848
+ target.addEventListener("lostpointercapture", onPointerCancel, eventOptions);
849
+ };
850
+ targets.forEach((target) => {
851
+ target = options.useGlobalTarget ? window : target;
852
+ let canAddKeyboardAccessibility = false;
853
+ if (target instanceof HTMLElement) {
854
+ canAddKeyboardAccessibility = true;
855
+ if (!isElementKeyboardAccessible(target) &&
856
+ target.getAttribute("tabindex") === null) {
857
+ target.tabIndex = 0;
889
858
  }
890
859
  }
891
- }
892
- getSize() {
893
- return this.subscriptions.length;
894
- }
895
- clear() {
896
- this.subscriptions.length = 0;
897
- }
898
- }
899
-
900
- /*
901
- Convert velocity into velocity per second
902
-
903
- @param [number]: Unit per frame
904
- @param [number]: Frame duration in ms
905
- */
906
- function velocityPerSecond(velocity, frameDuration) {
907
- return frameDuration ? velocity * (1000 / frameDuration) : 0;
860
+ target.addEventListener("pointerdown", startPress, eventOptions);
861
+ if (canAddKeyboardAccessibility) {
862
+ target.addEventListener("focus", (event) => enableKeyboardPress(event, eventOptions), eventOptions);
863
+ }
864
+ });
865
+ return cancelEvents;
908
866
  }
909
-
910
- const warned = new Set();
911
- function warnOnce(condition, message, element) {
912
- if (condition || warned.has(message))
913
- return;
914
- console.warn(message);
915
- if (element)
916
- console.warn(element);
917
- warned.add(message);
867
+ function checkOutside(event, rect) {
868
+ return (event.clientX < rect.left ||
869
+ event.clientX > rect.right ||
870
+ event.clientY < rect.top ||
871
+ event.clientY > rect.bottom);
918
872
  }
919
873
 
920
874
  /**
@@ -936,15 +890,13 @@ class MotionValue {
936
890
  * @param config - Optional configuration options
937
891
  *
938
892
  * - `transformer`: A function to transform incoming values with.
939
- *
940
- * @internal
941
893
  */
942
894
  constructor(init, options = {}) {
943
895
  /**
944
896
  * This will be replaced by the build step with the latest version number.
945
897
  * When MotionValues are provided to motion components, warn if versions are mixed.
946
898
  */
947
- this.version = "12.4.12";
899
+ this.version = "12.5.0";
948
900
  /**
949
901
  * Tracks whether this value can output a velocity. Currently this is only true
950
902
  * if the value is numerical, but we might be able to widen the scope here and support
@@ -1067,8 +1019,6 @@ class MotionValue {
1067
1019
  }
1068
1020
  /**
1069
1021
  * Attaches a passive effect to the `MotionValue`.
1070
- *
1071
- * @internal
1072
1022
  */
1073
1023
  attach(passiveEffect, stopPassiveEffect) {
1074
1024
  this.passiveEffect = passiveEffect;
@@ -1159,8 +1109,6 @@ class MotionValue {
1159
1109
  * ```
1160
1110
  *
1161
1111
  * @param animation - A function that starts the provided animation
1162
- *
1163
- * @internal
1164
1112
  */
1165
1113
  start(startAnimation) {
1166
1114
  this.stop();
@@ -1223,6 +1171,55 @@ function motionValue(init, options) {
1223
1171
  return new MotionValue(init, options);
1224
1172
  }
1225
1173
 
1174
+ /**
1175
+ * Generate a list of every possible transform key.
1176
+ */
1177
+ const transformPropOrder = [
1178
+ "transformPerspective",
1179
+ "x",
1180
+ "y",
1181
+ "z",
1182
+ "translateX",
1183
+ "translateY",
1184
+ "translateZ",
1185
+ "scale",
1186
+ "scaleX",
1187
+ "scaleY",
1188
+ "rotate",
1189
+ "rotateX",
1190
+ "rotateY",
1191
+ "rotateZ",
1192
+ "skew",
1193
+ "skewX",
1194
+ "skewY",
1195
+ ];
1196
+ /**
1197
+ * A quick lookup for transform props.
1198
+ */
1199
+ const transformProps = new Set(transformPropOrder);
1200
+
1201
+ const positionalKeys = new Set([
1202
+ "width",
1203
+ "height",
1204
+ "top",
1205
+ "left",
1206
+ "right",
1207
+ "bottom",
1208
+ ...transformPropOrder,
1209
+ ]);
1210
+
1211
+ const isKeyframesTarget = (v) => {
1212
+ return Array.isArray(v);
1213
+ };
1214
+
1215
+ const isCustomValue = (v) => {
1216
+ return Boolean(v && typeof v === "object" && v.mix && v.toValue);
1217
+ };
1218
+ const resolveFinalValueInKeyframes = (v) => {
1219
+ // TODO maybe throw if v.length - 1 is placeholder token?
1220
+ return isKeyframesTarget(v) ? v[v.length - 1] || 0 : v;
1221
+ };
1222
+
1226
1223
  /**
1227
1224
  * Set VisualElement's MotionValue, creating a new MotionValue for it if
1228
1225
  * it doesn't exist.
@@ -1780,25 +1777,89 @@ function makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, n
1780
1777
  }
1781
1778
  }
1782
1779
 
1783
- const isNumOrPxType = (v) => v === number || v === px;
1784
- const getPosFromMatrix = (matrix, pos) => parseFloat(matrix.split(", ")[pos]);
1785
- const getTranslateFromMatrix = (pos2, pos3) => (_bbox, { transform }) => {
1786
- if (transform === "none" || !transform)
1787
- return 0;
1788
- const matrix3d = transform.match(/^matrix3d\((.+)\)$/u);
1789
- if (matrix3d) {
1790
- return getPosFromMatrix(matrix3d[1], pos3);
1780
+ const radToDeg = (rad) => (rad * 180) / Math.PI;
1781
+ const rotate = (v) => {
1782
+ const angle = radToDeg(Math.atan2(v[1], v[0]));
1783
+ return rebaseAngle(angle);
1784
+ };
1785
+ const matrix2dParsers = {
1786
+ x: 4,
1787
+ y: 5,
1788
+ translateX: 4,
1789
+ translateY: 5,
1790
+ scaleX: 0,
1791
+ scaleY: 3,
1792
+ scale: (v) => (Math.abs(v[0]) + Math.abs(v[3])) / 2,
1793
+ rotate,
1794
+ rotateZ: rotate,
1795
+ skewX: (v) => radToDeg(Math.atan(v[1])),
1796
+ skewY: (v) => radToDeg(Math.atan(v[2])),
1797
+ skew: (v) => (Math.abs(v[1]) + Math.abs(v[2])) / 2,
1798
+ };
1799
+ const rebaseAngle = (angle) => {
1800
+ angle = angle % 360;
1801
+ if (angle < 0)
1802
+ angle += 360;
1803
+ return angle;
1804
+ };
1805
+ const rotateZ = rotate;
1806
+ const scaleX = (v) => Math.sqrt(v[0] * v[0] + v[1] * v[1]);
1807
+ const scaleY = (v) => Math.sqrt(v[4] * v[4] + v[5] * v[5]);
1808
+ const matrix3dParsers = {
1809
+ x: 12,
1810
+ y: 13,
1811
+ z: 14,
1812
+ translateX: 12,
1813
+ translateY: 13,
1814
+ translateZ: 14,
1815
+ scaleX,
1816
+ scaleY,
1817
+ scale: (v) => (scaleX(v) + scaleY(v)) / 2,
1818
+ rotateX: (v) => rebaseAngle(radToDeg(Math.atan2(v[6], v[5]))),
1819
+ rotateY: (v) => rebaseAngle(radToDeg(Math.atan2(-v[2], v[0]))),
1820
+ rotateZ,
1821
+ rotate: rotateZ,
1822
+ skewX: (v) => radToDeg(Math.atan(v[4])),
1823
+ skewY: (v) => radToDeg(Math.atan(v[1])),
1824
+ skew: (v) => (Math.abs(v[1]) + Math.abs(v[4])) / 2,
1825
+ };
1826
+ function defaultTransformValue(name) {
1827
+ return name.includes("scale") ? 1 : 0;
1828
+ }
1829
+ function parseValueFromTransform(transform, name) {
1830
+ if (!transform || transform === "none") {
1831
+ return defaultTransformValue(name);
1791
1832
  }
1792
- else {
1793
- const matrix = transform.match(/^matrix\((.+)\)$/u);
1794
- if (matrix) {
1795
- return getPosFromMatrix(matrix[1], pos2);
1796
- }
1797
- else {
1798
- return 0;
1799
- }
1833
+ const matrix3dMatch = transform.match(/^matrix3d\(([-\d.e\s,]+)\)$/u);
1834
+ let parsers;
1835
+ let match;
1836
+ if (matrix3dMatch) {
1837
+ parsers = matrix3dParsers;
1838
+ match = matrix3dMatch;
1800
1839
  }
1840
+ else {
1841
+ const matrix2dMatch = transform.match(/^matrix\(([-\d.e\s,]+)\)$/u);
1842
+ parsers = matrix2dParsers;
1843
+ match = matrix2dMatch;
1844
+ }
1845
+ if (!match) {
1846
+ return defaultTransformValue(name);
1847
+ }
1848
+ const valueParser = parsers[name];
1849
+ const values = match[1].split(",").map(convertTransformToNumber);
1850
+ return typeof valueParser === "function"
1851
+ ? valueParser(values)
1852
+ : values[valueParser];
1853
+ }
1854
+ const readTransformValue = (instance, name) => {
1855
+ const { transform = "none" } = getComputedStyle(instance);
1856
+ return parseValueFromTransform(transform, name);
1801
1857
  };
1858
+ function convertTransformToNumber(value) {
1859
+ return parseFloat(value.trim());
1860
+ }
1861
+
1862
+ const isNumOrPxType = (v) => v === number || v === px;
1802
1863
  const transformKeys = new Set(["x", "y", "z"]);
1803
1864
  const nonTranslationalTransformKeys = transformPropOrder.filter((key) => !transformKeys.has(key));
1804
1865
  function removeNonTranslationalTransform(visualElement) {
@@ -1821,8 +1882,8 @@ const positionalValues = {
1821
1882
  bottom: ({ y }, { top }) => parseFloat(top) + (y.max - y.min),
1822
1883
  right: ({ x }, { left }) => parseFloat(left) + (x.max - x.min),
1823
1884
  // Transform
1824
- x: getTranslateFromMatrix(4, 13),
1825
- y: getTranslateFromMatrix(5, 14),
1885
+ x: (_bbox, { transform }) => parseValueFromTransform(transform, "x"),
1886
+ y: (_bbox, { transform }) => parseValueFromTransform(transform, "y"),
1826
1887
  };
1827
1888
  // Alias translate longform names
1828
1889
  positionalValues.translateX = positionalValues.x;
@@ -5758,8 +5819,6 @@ const LayoutGroupContext = react.createContext({});
5758
5819
  */
5759
5820
  const SwitchLayoutGroupContext = react.createContext({});
5760
5821
 
5761
- const { schedule: microtask, cancel: cancelMicrotask } = createRenderBatcher(queueMicrotask, false);
5762
-
5763
5822
  /**
5764
5823
  * This should only ever be modified on the client otherwise it'll
5765
5824
  * persist through server requests. If we need instanced states we
@@ -9315,7 +9374,7 @@ function updateMotionValuesFromProps(element, next, prev) {
9315
9374
  * and warn against mismatches.
9316
9375
  */
9317
9376
  if (process.env.NODE_ENV === "development") {
9318
- warnOnce(nextValue.version === "12.4.12", `Attempting to mix Motion versions ${nextValue.version} with 12.4.12 may not work as expected.`);
9377
+ warnOnce(nextValue.version === "12.5.0", `Attempting to mix Motion versions ${nextValue.version} with 12.5.0 may not work as expected.`);
9319
9378
  }
9320
9379
  }
9321
9380
  else if (isMotionValue(prevValue)) {
@@ -9850,7 +9909,7 @@ class DOMVisualElement extends VisualElement {
9850
9909
  }
9851
9910
  }
9852
9911
 
9853
- function getComputedStyle(element) {
9912
+ function getComputedStyle$1(element) {
9854
9913
  return window.getComputedStyle(element);
9855
9914
  }
9856
9915
  class HTMLVisualElement extends DOMVisualElement {
@@ -9861,11 +9920,10 @@ class HTMLVisualElement extends DOMVisualElement {
9861
9920
  }
9862
9921
  readValueFromInstance(instance, key) {
9863
9922
  if (transformProps.has(key)) {
9864
- const defaultType = getDefaultValueType(key);
9865
- return defaultType ? defaultType.default || 0 : 0;
9923
+ return readTransformValue(instance, key);
9866
9924
  }
9867
9925
  else {
9868
- const computedStyle = getComputedStyle(instance);
9926
+ const computedStyle = getComputedStyle$1(instance);
9869
9927
  const value = (isCSSVariableName(key)
9870
9928
  ? computedStyle.getPropertyValue(key)
9871
9929
  : computedStyle[key]) || 0;