motion 12.11.4 → 12.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/cjs/index.js +110 -16
  2. package/dist/cjs/react-client.js +141 -120
  3. package/dist/cjs/react-m.js +108 -108
  4. package/dist/es/framer-motion/dist/es/animation/animate/single-value.mjs +1 -1
  5. package/dist/es/framer-motion/dist/es/animation/animate/subject.mjs +1 -1
  6. package/dist/es/framer-motion/dist/es/animation/sequence/create.mjs +1 -1
  7. package/dist/es/framer-motion/dist/es/animation/utils/create-visual-element.mjs +3 -2
  8. package/dist/es/framer-motion/dist/es/components/AnimatePresence/PopChild.mjs +4 -1
  9. package/dist/es/framer-motion/dist/es/components/Reorder/Item.mjs +1 -1
  10. package/dist/es/framer-motion/dist/es/projection/node/create-projection-node.mjs +3 -2
  11. package/dist/es/framer-motion/dist/es/render/VisualElement.mjs +1 -1
  12. package/dist/es/framer-motion/dist/es/render/dom/DOMVisualElement.mjs +1 -1
  13. package/dist/es/framer-motion/dist/es/render/dom/resize/handle-element.mjs +2 -1
  14. package/dist/es/framer-motion/dist/es/render/dom/scroll/offsets/inset.mjs +3 -1
  15. package/dist/es/framer-motion/dist/es/render/dom/use-render.mjs +2 -2
  16. package/dist/es/framer-motion/dist/es/render/html/use-props.mjs +1 -1
  17. package/dist/es/framer-motion/dist/es/render/html/utils/scrape-motion-values.mjs +1 -1
  18. package/dist/es/framer-motion/dist/es/render/svg/utils/scrape-motion-values.mjs +1 -1
  19. package/dist/es/framer-motion/dist/es/render/utils/motion-values.mjs +1 -1
  20. package/dist/es/framer-motion/dist/es/value/use-motion-template.mjs +1 -1
  21. package/dist/es/framer-motion/dist/es/value/use-spring.mjs +13 -53
  22. package/dist/es/framer-motion/dist/es/value/use-will-change/is.mjs +1 -1
  23. package/dist/es/framer-motion/dist/es/value/utils/resolve-motion-value.mjs +1 -1
  24. package/dist/es/motion/lib/index.mjs +6 -0
  25. package/dist/es/motion/lib/react.mjs +6 -1
  26. package/dist/es/motion-dom/dist/es/animation/waapi/supports/waapi.mjs +3 -5
  27. package/dist/es/motion-dom/dist/es/gestures/press/index.mjs +2 -1
  28. package/dist/es/motion-dom/dist/es/utils/interpolate.mjs +1 -1
  29. package/dist/es/motion-dom/dist/es/utils/is-html-element.mjs +11 -0
  30. package/dist/es/motion-dom/dist/es/utils/is-svg-element.mjs +11 -0
  31. package/dist/es/motion-dom/dist/es/utils/is-svg-svg-element.mjs +11 -0
  32. package/dist/es/motion-dom/dist/es/value/spring-value.mjs +72 -0
  33. package/dist/es/motion-utils/dist/es/is-object.mjs +5 -0
  34. package/dist/motion.dev.js +110 -16
  35. package/dist/motion.js +1 -1
  36. package/package.json +3 -3
  37. package/dist/es/framer-motion/dist/es/render/dom/utils/is-svg-element.mjs +0 -5
  38. /package/dist/es/{framer-motion → motion-dom}/dist/es/value/utils/is-motion-value.mjs +0 -0
package/dist/cjs/index.js CHANGED
@@ -52,6 +52,10 @@ const MotionGlobalConfig = {};
52
52
  */
53
53
  const isNumericalString = (v) => /^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(v);
54
54
 
55
+ function isObject(value) {
56
+ return typeof value === "object" && value !== null;
57
+ }
58
+
55
59
  /**
56
60
  * Check if the value is a zero value string like "0px" or "0%"
57
61
  */
@@ -1423,7 +1427,7 @@ function createMixers(output, ease, customMixer) {
1423
1427
  * mixColor(0.5) // 'rgba(128, 128, 128, 1)'
1424
1428
  * ```
1425
1429
  *
1426
- * TODO Revist this approach once we've moved to data models for values,
1430
+ * TODO Revisit this approach once we've moved to data models for values,
1427
1431
  * probably not needed to pregenerate mixer functions.
1428
1432
  *
1429
1433
  * @public
@@ -2596,6 +2600,14 @@ function canAnimate(keyframes, name, type, velocity) {
2596
2600
  ((type === "spring" || isGenerator(type)) && velocity));
2597
2601
  }
2598
2602
 
2603
+ /**
2604
+ * Checks if an element is an HTML element in a way
2605
+ * that works across iframes
2606
+ */
2607
+ function isHTMLElement(element) {
2608
+ return isObject(element) && "offsetHeight" in element;
2609
+ }
2610
+
2599
2611
  /**
2600
2612
  * A list of values that can be hardware-accelerated.
2601
2613
  */
@@ -2604,16 +2616,13 @@ const acceleratedValues$1 = new Set([
2604
2616
  "clipPath",
2605
2617
  "filter",
2606
2618
  "transform",
2607
- // TODO: Can be accelerated but currently disabled until https://issues.chromium.org/issues/41491098 is resolved
2608
- // or until we implement support for linear() easing.
2619
+ // TODO: Could be re-enabled now we have support for linear() easing
2609
2620
  // "background-color"
2610
2621
  ]);
2611
2622
  const supportsWaapi = /*@__PURE__*/ memo(() => Object.hasOwnProperty.call(Element.prototype, "animate"));
2612
2623
  function supportsBrowserAnimation(options) {
2613
2624
  const { motionValue, name, repeatDelay, repeatType, damping, type } = options;
2614
- if (!motionValue ||
2615
- !motionValue.owner ||
2616
- !(motionValue.owner.current instanceof HTMLElement)) {
2625
+ if (!isHTMLElement(motionValue?.owner?.current)) {
2617
2626
  return false;
2618
2627
  }
2619
2628
  const { onUpdate, transformTemplate } = motionValue.owner.getProps();
@@ -4029,7 +4038,7 @@ function press(targetOrSelector, onPressStart, options = {}) {
4029
4038
  targets.forEach((target) => {
4030
4039
  const pointerDownTarget = options.useGlobalTarget ? window : target;
4031
4040
  pointerDownTarget.addEventListener("pointerdown", startPress, eventOptions);
4032
- if (target instanceof HTMLElement) {
4041
+ if (isHTMLElement(target)) {
4033
4042
  target.addEventListener("focus", (event) => enableKeyboardPress(event, eventOptions));
4034
4043
  if (!isElementKeyboardAccessible(target) &&
4035
4044
  !target.hasAttribute("tabindex")) {
@@ -4174,6 +4183,22 @@ function recordStats() {
4174
4183
  return reportStats;
4175
4184
  }
4176
4185
 
4186
+ /**
4187
+ * Checks if an element is an SVG element in a way
4188
+ * that works across iframes
4189
+ */
4190
+ function isSVGElement(element) {
4191
+ return isObject(element) && "ownerSVGElement" in element;
4192
+ }
4193
+
4194
+ /**
4195
+ * Checks if an element is specifically an SVGSVGElement (the root SVG element)
4196
+ * in a way that works across iframes
4197
+ */
4198
+ function isSVGSVGElement(element) {
4199
+ return isSVGElement(element) && element.tagName === "svg";
4200
+ }
4201
+
4177
4202
  function transform(...args) {
4178
4203
  const useImmediate = !Array.isArray(args[0]);
4179
4204
  const argOffset = useImmediate ? 0 : -1;
@@ -4268,6 +4293,74 @@ function mapValue(inputValue, inputRange, outputRange, options) {
4268
4293
  return transformValue(() => map(inputValue.get()));
4269
4294
  }
4270
4295
 
4296
+ const isMotionValue = (value) => Boolean(value && value.getVelocity);
4297
+
4298
+ /**
4299
+ * Create a `MotionValue` that animates to its latest value using a spring.
4300
+ * Can either be a value or track another `MotionValue`.
4301
+ *
4302
+ * ```jsx
4303
+ * const x = motionValue(0)
4304
+ * const y = transformValue(() => x.get() * 2) // double x
4305
+ * ```
4306
+ *
4307
+ * @param transformer - A transform function. This function must be pure with no side-effects or conditional statements.
4308
+ * @returns `MotionValue`
4309
+ *
4310
+ * @public
4311
+ */
4312
+ function springValue(source, options) {
4313
+ const initialValue = isMotionValue(source) ? source.get() : source;
4314
+ const value = motionValue(initialValue);
4315
+ attachSpring(value, source, options);
4316
+ return value;
4317
+ }
4318
+ function attachSpring(value, source, options) {
4319
+ const initialValue = value.get();
4320
+ let activeAnimation = null;
4321
+ let latestValue = initialValue;
4322
+ let latestSetter;
4323
+ const unit = typeof initialValue === "string"
4324
+ ? initialValue.replace(/[\d.-]/g, "")
4325
+ : undefined;
4326
+ const stopAnimation = () => {
4327
+ if (activeAnimation) {
4328
+ activeAnimation.stop();
4329
+ activeAnimation = null;
4330
+ }
4331
+ };
4332
+ const startAnimation = () => {
4333
+ stopAnimation();
4334
+ activeAnimation = new JSAnimation({
4335
+ keyframes: [asNumber(value.get()), asNumber(latestValue)],
4336
+ velocity: value.getVelocity(),
4337
+ type: "spring",
4338
+ restDelta: 0.001,
4339
+ restSpeed: 0.01,
4340
+ ...options,
4341
+ onUpdate: latestSetter,
4342
+ });
4343
+ };
4344
+ value.attach((v, set) => {
4345
+ latestValue = v;
4346
+ latestSetter = (latest) => set(parseValue(latest, unit));
4347
+ frame.postRender(startAnimation);
4348
+ return value.get();
4349
+ }, stopAnimation);
4350
+ let unsubscribe = undefined;
4351
+ if (isMotionValue(source)) {
4352
+ unsubscribe = source.on("change", (v) => value.set(parseValue(v, unit)));
4353
+ value.on("destroy", unsubscribe);
4354
+ }
4355
+ return unsubscribe;
4356
+ }
4357
+ function parseValue(v, unit) {
4358
+ return unit ? v + unit : v;
4359
+ }
4360
+ function asNumber(v) {
4361
+ return typeof v === "number" ? v : parseFloat(v);
4362
+ }
4363
+
4271
4364
  /**
4272
4365
  * A list of all ValueTypes
4273
4366
  */
@@ -4604,8 +4697,6 @@ const cancelSync = stepsOrder.reduce((acc, key) => {
4604
4697
  return acc;
4605
4698
  }, {});
4606
4699
 
4607
- const isMotionValue = (value) => Boolean(value && value.getVelocity);
4608
-
4609
4700
  function isDOMKeyframes(keyframes) {
4610
4701
  return typeof keyframes === "object" && !Array.isArray(keyframes);
4611
4702
  }
@@ -5266,10 +5357,6 @@ function animateTarget(visualElement, targetAndTransition, { delay = 0, transiti
5266
5357
  return animations;
5267
5358
  }
5268
5359
 
5269
- function isSVGElement(element) {
5270
- return element instanceof SVGElement && element.tagName !== "svg";
5271
- }
5272
-
5273
5360
  /**
5274
5361
  * Bounding boxes tend to be defined as top, left, right, bottom. For various operations
5275
5362
  * it's easier to consider each axis individually. This function returns a bounding box
@@ -6329,7 +6416,7 @@ function createDOMVisualElement(element) {
6329
6416
  latestValues: {},
6330
6417
  },
6331
6418
  };
6332
- const node = isSVGElement(element)
6419
+ const node = isSVGElement(element) && !isSVGSVGElement(element)
6333
6420
  ? new SVGVisualElement(options)
6334
6421
  : new HTMLVisualElement(options);
6335
6422
  node.mount(element);
@@ -6553,7 +6640,7 @@ function getElementSize(target, borderBoxSize) {
6553
6640
  const { inlineSize, blockSize } = borderBoxSize[0];
6554
6641
  return { width: inlineSize, height: blockSize };
6555
6642
  }
6556
- else if (target instanceof SVGElement && "getBBox" in target) {
6643
+ else if (isSVGElement(target) && "getBBox" in target) {
6557
6644
  return target.getBBox();
6558
6645
  }
6559
6646
  else {
@@ -6695,7 +6782,7 @@ function calcInset(element, container) {
6695
6782
  const inset = { x: 0, y: 0 };
6696
6783
  let current = element;
6697
6784
  while (current && current !== container) {
6698
- if (current instanceof HTMLElement) {
6785
+ if (isHTMLElement(current)) {
6699
6786
  inset.x += current.offsetLeft;
6700
6787
  inset.y += current.offsetTop;
6701
6788
  current = current.offsetParent;
@@ -7186,6 +7273,7 @@ exports.animateView = animateView;
7186
7273
  exports.animationMapKey = animationMapKey;
7187
7274
  exports.anticipate = anticipate;
7188
7275
  exports.applyPxDefaults = applyPxDefaults;
7276
+ exports.attachSpring = attachSpring;
7189
7277
  exports.backIn = backIn;
7190
7278
  exports.backInOut = backInOut;
7191
7279
  exports.backOut = backOut;
@@ -7253,9 +7341,14 @@ exports.isDragActive = isDragActive;
7253
7341
  exports.isDragging = isDragging;
7254
7342
  exports.isEasingArray = isEasingArray;
7255
7343
  exports.isGenerator = isGenerator;
7344
+ exports.isHTMLElement = isHTMLElement;
7345
+ exports.isMotionValue = isMotionValue;
7256
7346
  exports.isNodeOrChild = isNodeOrChild;
7257
7347
  exports.isNumericalString = isNumericalString;
7348
+ exports.isObject = isObject;
7258
7349
  exports.isPrimaryPointer = isPrimaryPointer;
7350
+ exports.isSVGElement = isSVGElement;
7351
+ exports.isSVGSVGElement = isSVGSVGElement;
7259
7352
  exports.isWaapiSupportedEasing = isWaapiSupportedEasing;
7260
7353
  exports.isZeroValueString = isZeroValueString;
7261
7354
  exports.keyframes = keyframes;
@@ -7304,6 +7397,7 @@ exports.secondsToMilliseconds = secondsToMilliseconds;
7304
7397
  exports.setDragLock = setDragLock;
7305
7398
  exports.setStyle = setStyle;
7306
7399
  exports.spring = spring;
7400
+ exports.springValue = springValue;
7307
7401
  exports.stagger = stagger;
7308
7402
  exports.startWaapiAnimation = startWaapiAnimation;
7309
7403
  exports.statsBuffer = statsBuffer;
@@ -91,6 +91,10 @@ const MotionGlobalConfig = {};
91
91
  */
92
92
  const isNumericalString = (v) => /^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(v);
93
93
 
94
+ function isObject(value) {
95
+ return typeof value === "object" && value !== null;
96
+ }
97
+
94
98
  /**
95
99
  * Check if the value is a zero value string like "0px" or "0%"
96
100
  */
@@ -1432,7 +1436,7 @@ function createMixers(output, ease, customMixer) {
1432
1436
  * mixColor(0.5) // 'rgba(128, 128, 128, 1)'
1433
1437
  * ```
1434
1438
  *
1435
- * TODO Revist this approach once we've moved to data models for values,
1439
+ * TODO Revisit this approach once we've moved to data models for values,
1436
1440
  * probably not needed to pregenerate mixer functions.
1437
1441
  *
1438
1442
  * @public
@@ -2591,6 +2595,14 @@ function canAnimate(keyframes, name, type, velocity) {
2591
2595
  ((type === "spring" || isGenerator(type)) && velocity));
2592
2596
  }
2593
2597
 
2598
+ /**
2599
+ * Checks if an element is an HTML element in a way
2600
+ * that works across iframes
2601
+ */
2602
+ function isHTMLElement(element) {
2603
+ return isObject(element) && "offsetHeight" in element;
2604
+ }
2605
+
2594
2606
  /**
2595
2607
  * A list of values that can be hardware-accelerated.
2596
2608
  */
@@ -2599,16 +2611,13 @@ const acceleratedValues = new Set([
2599
2611
  "clipPath",
2600
2612
  "filter",
2601
2613
  "transform",
2602
- // TODO: Can be accelerated but currently disabled until https://issues.chromium.org/issues/41491098 is resolved
2603
- // or until we implement support for linear() easing.
2614
+ // TODO: Could be re-enabled now we have support for linear() easing
2604
2615
  // "background-color"
2605
2616
  ]);
2606
2617
  const supportsWaapi = /*@__PURE__*/ memo(() => Object.hasOwnProperty.call(Element.prototype, "animate"));
2607
2618
  function supportsBrowserAnimation(options) {
2608
2619
  const { motionValue, name, repeatDelay, repeatType, damping, type } = options;
2609
- if (!motionValue ||
2610
- !motionValue.owner ||
2611
- !(motionValue.owner.current instanceof HTMLElement)) {
2620
+ if (!isHTMLElement(motionValue?.owner?.current)) {
2612
2621
  return false;
2613
2622
  }
2614
2623
  const { onUpdate, transformTemplate } = motionValue.owner.getProps();
@@ -3730,7 +3739,7 @@ function press(targetOrSelector, onPressStart, options = {}) {
3730
3739
  targets.forEach((target) => {
3731
3740
  const pointerDownTarget = options.useGlobalTarget ? window : target;
3732
3741
  pointerDownTarget.addEventListener("pointerdown", startPress, eventOptions);
3733
- if (target instanceof HTMLElement) {
3742
+ if (isHTMLElement(target)) {
3734
3743
  target.addEventListener("focus", (event) => enableKeyboardPress(event, eventOptions));
3735
3744
  if (!isElementKeyboardAccessible(target) &&
3736
3745
  !target.hasAttribute("tabindex")) {
@@ -3741,6 +3750,24 @@ function press(targetOrSelector, onPressStart, options = {}) {
3741
3750
  return cancelEvents;
3742
3751
  }
3743
3752
 
3753
+ /**
3754
+ * Checks if an element is an SVG element in a way
3755
+ * that works across iframes
3756
+ */
3757
+ function isSVGElement(element) {
3758
+ return isObject(element) && "ownerSVGElement" in element;
3759
+ }
3760
+
3761
+ /**
3762
+ * Checks if an element is specifically an SVGSVGElement (the root SVG element)
3763
+ * in a way that works across iframes
3764
+ */
3765
+ function isSVGSVGElement(element) {
3766
+ return isSVGElement(element) && element.tagName === "svg";
3767
+ }
3768
+
3769
+ const isMotionValue = (value) => Boolean(value && value.getVelocity);
3770
+
3744
3771
  /**
3745
3772
  * A list of all ValueTypes
3746
3773
  */
@@ -3780,8 +3807,6 @@ function setTarget(visualElement, definition) {
3780
3807
  }
3781
3808
  }
3782
3809
 
3783
- const isMotionValue = (value) => Boolean(value && value.getVelocity);
3784
-
3785
3810
  function isWillChangeMotionValue(value) {
3786
3811
  return Boolean(isMotionValue(value) && value.add);
3787
3812
  }
@@ -5955,10 +5980,6 @@ function animateSingleValue(value, keyframes, options) {
5955
5980
  return motionValue$1.animation;
5956
5981
  }
5957
5982
 
5958
- function isSVGElement(element) {
5959
- return element instanceof SVGElement && element.tagName !== "svg";
5960
- }
5961
-
5962
5983
  const compareByDepth = (a, b) => a.depth - b.depth;
5963
5984
 
5964
5985
  class FlatTree {
@@ -6550,7 +6571,7 @@ function createProjectionNode$1({ attachResizeListener, defaultParent, measureSc
6550
6571
  mount(instance) {
6551
6572
  if (this.instance)
6552
6573
  return;
6553
- this.isSVG = isSVGElement(instance);
6574
+ this.isSVG = isSVGElement(instance) && !isSVGSVGElement(instance);
6554
6575
  this.instance = instance;
6555
6576
  const { layoutId, layout, visualElement } = this.options;
6556
6577
  if (visualElement && !visualElement.current) {
@@ -8652,6 +8673,112 @@ function useHTMLProps(props, visualState) {
8652
8673
  return htmlProps;
8653
8674
  }
8654
8675
 
8676
+ const dashKeys = {
8677
+ offset: "stroke-dashoffset",
8678
+ array: "stroke-dasharray",
8679
+ };
8680
+ const camelKeys = {
8681
+ offset: "strokeDashoffset",
8682
+ array: "strokeDasharray",
8683
+ };
8684
+ /**
8685
+ * Build SVG path properties. Uses the path's measured length to convert
8686
+ * our custom pathLength, pathSpacing and pathOffset into stroke-dashoffset
8687
+ * and stroke-dasharray attributes.
8688
+ *
8689
+ * This function is mutative to reduce per-frame GC.
8690
+ */
8691
+ function buildSVGPath(attrs, length, spacing = 1, offset = 0, useDashCase = true) {
8692
+ // Normalise path length by setting SVG attribute pathLength to 1
8693
+ attrs.pathLength = 1;
8694
+ // We use dash case when setting attributes directly to the DOM node and camel case
8695
+ // when defining props on a React component.
8696
+ const keys = useDashCase ? dashKeys : camelKeys;
8697
+ // Build the dash offset
8698
+ attrs[keys.offset] = px.transform(-offset);
8699
+ // Build the dash array
8700
+ const pathLength = px.transform(length);
8701
+ const pathSpacing = px.transform(spacing);
8702
+ attrs[keys.array] = `${pathLength} ${pathSpacing}`;
8703
+ }
8704
+
8705
+ /**
8706
+ * Build SVG visual attrbutes, like cx and style.transform
8707
+ */
8708
+ function buildSVGAttrs(state, { attrX, attrY, attrScale, pathLength, pathSpacing = 1, pathOffset = 0,
8709
+ // This is object creation, which we try to avoid per-frame.
8710
+ ...latest }, isSVGTag, transformTemplate, styleProp) {
8711
+ buildHTMLStyles(state, latest, transformTemplate);
8712
+ /**
8713
+ * For svg tags we just want to make sure viewBox is animatable and treat all the styles
8714
+ * as normal HTML tags.
8715
+ */
8716
+ if (isSVGTag) {
8717
+ if (state.style.viewBox) {
8718
+ state.attrs.viewBox = state.style.viewBox;
8719
+ }
8720
+ return;
8721
+ }
8722
+ state.attrs = state.style;
8723
+ state.style = {};
8724
+ const { attrs, style } = state;
8725
+ /**
8726
+ * However, we apply transforms as CSS transforms.
8727
+ * So if we detect a transform, transformOrigin we take it from attrs and copy it into style.
8728
+ */
8729
+ if (attrs.transform) {
8730
+ style.transform = attrs.transform;
8731
+ delete attrs.transform;
8732
+ }
8733
+ if (style.transform || attrs.transformOrigin) {
8734
+ style.transformOrigin = attrs.transformOrigin ?? "50% 50%";
8735
+ delete attrs.transformOrigin;
8736
+ }
8737
+ if (style.transform) {
8738
+ /**
8739
+ * SVG's element transform-origin uses its own median as a reference.
8740
+ * Therefore, transformBox becomes a fill-box
8741
+ */
8742
+ style.transformBox = styleProp?.transformBox ?? "fill-box";
8743
+ delete attrs.transformBox;
8744
+ }
8745
+ // Render attrX/attrY/attrScale as attributes
8746
+ if (attrX !== undefined)
8747
+ attrs.x = attrX;
8748
+ if (attrY !== undefined)
8749
+ attrs.y = attrY;
8750
+ if (attrScale !== undefined)
8751
+ attrs.scale = attrScale;
8752
+ // Build SVG path if one has been defined
8753
+ if (pathLength !== undefined) {
8754
+ buildSVGPath(attrs, pathLength, pathSpacing, pathOffset, false);
8755
+ }
8756
+ }
8757
+
8758
+ const createSvgRenderState = () => ({
8759
+ ...createHtmlRenderState(),
8760
+ attrs: {},
8761
+ });
8762
+
8763
+ const isSVGTag = (tag) => typeof tag === "string" && tag.toLowerCase() === "svg";
8764
+
8765
+ function useSVGProps(props, visualState, _isStatic, Component) {
8766
+ const visualProps = react.useMemo(() => {
8767
+ const state = createSvgRenderState();
8768
+ buildSVGAttrs(state, visualState, isSVGTag(Component), props.transformTemplate, props.style);
8769
+ return {
8770
+ ...state.attrs,
8771
+ style: { ...state.style },
8772
+ };
8773
+ }, [visualState]);
8774
+ if (props.style) {
8775
+ const rawStyles = {};
8776
+ copyRawValuesOnly(rawStyles, props.style, props);
8777
+ visualProps.style = { ...rawStyles, ...visualProps.style };
8778
+ }
8779
+ return visualProps;
8780
+ }
8781
+
8655
8782
  /**
8656
8783
  * A list of all valid MotionProps.
8657
8784
  *
@@ -8823,112 +8950,6 @@ function isSVGComponent(Component) {
8823
8950
  return false;
8824
8951
  }
8825
8952
 
8826
- const dashKeys = {
8827
- offset: "stroke-dashoffset",
8828
- array: "stroke-dasharray",
8829
- };
8830
- const camelKeys = {
8831
- offset: "strokeDashoffset",
8832
- array: "strokeDasharray",
8833
- };
8834
- /**
8835
- * Build SVG path properties. Uses the path's measured length to convert
8836
- * our custom pathLength, pathSpacing and pathOffset into stroke-dashoffset
8837
- * and stroke-dasharray attributes.
8838
- *
8839
- * This function is mutative to reduce per-frame GC.
8840
- */
8841
- function buildSVGPath(attrs, length, spacing = 1, offset = 0, useDashCase = true) {
8842
- // Normalise path length by setting SVG attribute pathLength to 1
8843
- attrs.pathLength = 1;
8844
- // We use dash case when setting attributes directly to the DOM node and camel case
8845
- // when defining props on a React component.
8846
- const keys = useDashCase ? dashKeys : camelKeys;
8847
- // Build the dash offset
8848
- attrs[keys.offset] = px.transform(-offset);
8849
- // Build the dash array
8850
- const pathLength = px.transform(length);
8851
- const pathSpacing = px.transform(spacing);
8852
- attrs[keys.array] = `${pathLength} ${pathSpacing}`;
8853
- }
8854
-
8855
- /**
8856
- * Build SVG visual attrbutes, like cx and style.transform
8857
- */
8858
- function buildSVGAttrs(state, { attrX, attrY, attrScale, pathLength, pathSpacing = 1, pathOffset = 0,
8859
- // This is object creation, which we try to avoid per-frame.
8860
- ...latest }, isSVGTag, transformTemplate, styleProp) {
8861
- buildHTMLStyles(state, latest, transformTemplate);
8862
- /**
8863
- * For svg tags we just want to make sure viewBox is animatable and treat all the styles
8864
- * as normal HTML tags.
8865
- */
8866
- if (isSVGTag) {
8867
- if (state.style.viewBox) {
8868
- state.attrs.viewBox = state.style.viewBox;
8869
- }
8870
- return;
8871
- }
8872
- state.attrs = state.style;
8873
- state.style = {};
8874
- const { attrs, style } = state;
8875
- /**
8876
- * However, we apply transforms as CSS transforms.
8877
- * So if we detect a transform, transformOrigin we take it from attrs and copy it into style.
8878
- */
8879
- if (attrs.transform) {
8880
- style.transform = attrs.transform;
8881
- delete attrs.transform;
8882
- }
8883
- if (style.transform || attrs.transformOrigin) {
8884
- style.transformOrigin = attrs.transformOrigin ?? "50% 50%";
8885
- delete attrs.transformOrigin;
8886
- }
8887
- if (style.transform) {
8888
- /**
8889
- * SVG's element transform-origin uses its own median as a reference.
8890
- * Therefore, transformBox becomes a fill-box
8891
- */
8892
- style.transformBox = styleProp?.transformBox ?? "fill-box";
8893
- delete attrs.transformBox;
8894
- }
8895
- // Render attrX/attrY/attrScale as attributes
8896
- if (attrX !== undefined)
8897
- attrs.x = attrX;
8898
- if (attrY !== undefined)
8899
- attrs.y = attrY;
8900
- if (attrScale !== undefined)
8901
- attrs.scale = attrScale;
8902
- // Build SVG path if one has been defined
8903
- if (pathLength !== undefined) {
8904
- buildSVGPath(attrs, pathLength, pathSpacing, pathOffset, false);
8905
- }
8906
- }
8907
-
8908
- const createSvgRenderState = () => ({
8909
- ...createHtmlRenderState(),
8910
- attrs: {},
8911
- });
8912
-
8913
- const isSVGTag = (tag) => typeof tag === "string" && tag.toLowerCase() === "svg";
8914
-
8915
- function useSVGProps(props, visualState, _isStatic, Component) {
8916
- const visualProps = react.useMemo(() => {
8917
- const state = createSvgRenderState();
8918
- buildSVGAttrs(state, visualState, isSVGTag(Component), props.transformTemplate, props.style);
8919
- return {
8920
- ...state.attrs,
8921
- style: { ...state.style },
8922
- };
8923
- }, [visualState]);
8924
- if (props.style) {
8925
- const rawStyles = {};
8926
- copyRawValuesOnly(rawStyles, props.style, props);
8927
- visualProps.style = { ...rawStyles, ...visualProps.style };
8928
- }
8929
- return visualProps;
8930
- }
8931
-
8932
8953
  function createUseRender(forwardMotionProps = false) {
8933
8954
  const useRender = (Component, props, ref, { latestValues }, isStatic) => {
8934
8955
  const useVisualProps = isSVGComponent(Component)