motion 12.0.5 → 12.0.8-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.
@@ -548,212 +548,11 @@ function getProjectionFunctionality(props) {
548
548
  };
549
549
  }
550
550
 
551
- /**
552
- * We keep these listed separately as we use the lowercase tag names as part
553
- * of the runtime bundle to detect SVG components
554
- */
555
- const lowercaseSVGElements = [
556
- "animate",
557
- "circle",
558
- "defs",
559
- "desc",
560
- "ellipse",
561
- "g",
562
- "image",
563
- "line",
564
- "filter",
565
- "marker",
566
- "mask",
567
- "metadata",
568
- "path",
569
- "pattern",
570
- "polygon",
571
- "polyline",
572
- "rect",
573
- "stop",
574
- "switch",
575
- "symbol",
576
- "svg",
577
- "text",
578
- "tspan",
579
- "use",
580
- "view",
581
- ];
582
-
583
- function isSVGComponent(Component) {
584
- if (
585
- /**
586
- * If it's not a string, it's a custom React component. Currently we only support
587
- * HTML custom React components.
588
- */
589
- typeof Component !== "string" ||
590
- /**
591
- * If it contains a dash, the element is a custom HTML webcomponent.
592
- */
593
- Component.includes("-")) {
594
- return false;
595
- }
596
- else if (
597
- /**
598
- * If it's in our list of lowercase SVG tags, it's an SVG component
599
- */
600
- lowercaseSVGElements.indexOf(Component) > -1 ||
601
- /**
602
- * If it contains a capital letter, it's an SVG component
603
- */
604
- /[A-Z]/u.test(Component)) {
605
- return true;
606
- }
607
- return false;
608
- }
609
-
610
- const { schedule: frame, cancel: cancelFrame, state: frameData, steps: frameSteps, } = createRenderBatcher(typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : noop, true);
611
-
612
- function getValueState(visualElement) {
613
- const state = [{}, {}];
614
- visualElement === null || visualElement === void 0 ? void 0 : visualElement.values.forEach((value, key) => {
615
- state[0][key] = value.get();
616
- state[1][key] = value.getVelocity();
617
- });
618
- return state;
619
- }
620
- function resolveVariantFromProps(props, definition, custom, visualElement) {
621
- /**
622
- * If the variant definition is a function, resolve.
623
- */
624
- if (typeof definition === "function") {
625
- const [current, velocity] = getValueState(visualElement);
626
- definition = definition(custom !== undefined ? custom : props.custom, current, velocity);
627
- }
628
- /**
629
- * If the variant definition is a variant label, or
630
- * the function returned a variant label, resolve.
631
- */
632
- if (typeof definition === "string") {
633
- definition = props.variants && props.variants[definition];
634
- }
635
- /**
636
- * At this point we've resolved both functions and variant labels,
637
- * but the resolved variant label might itself have been a function.
638
- * If so, resolve. This can only have returned a valid target object.
639
- */
640
- if (typeof definition === "function") {
641
- const [current, velocity] = getValueState(visualElement);
642
- definition = definition(custom !== undefined ? custom : props.custom, current, velocity);
643
- }
644
- return definition;
645
- }
646
-
647
- /**
648
- * Creates a constant value over the lifecycle of a component.
649
- *
650
- * Even if `useMemo` is provided an empty array as its final argument, it doesn't offer
651
- * a guarantee that it won't re-run for performance reasons later on. By using `useConstant`
652
- * you can ensure that initialisers don't execute twice or more.
653
- */
654
- function useConstant(init) {
655
- const ref = react.useRef(null);
656
- if (ref.current === null) {
657
- ref.current = init();
658
- }
659
- return ref.current;
660
- }
661
-
662
- const isCustomValue = (v) => {
663
- return Boolean(v && typeof v === "object" && v.mix && v.toValue);
664
- };
665
-
666
- const isMotionValue = (value) => Boolean(value && value.getVelocity);
667
-
668
- /**
669
- * If the provided value is a MotionValue, this returns the actual value, otherwise just the value itself
670
- *
671
- * TODO: Remove and move to library
672
- */
673
- function resolveMotionValue(value) {
674
- const unwrappedValue = isMotionValue(value) ? value.get() : value;
675
- return isCustomValue(unwrappedValue)
676
- ? unwrappedValue.toValue()
677
- : unwrappedValue;
678
- }
551
+ const checkStringStartsWith = (token) => (key) => typeof key === "string" && key.startsWith(token);
552
+ const isCSSVariableName =
553
+ /*@__PURE__*/ checkStringStartsWith("--");
679
554
 
680
- function makeState({ scrapeMotionValuesFromProps, createRenderState, onUpdate, }, props, context, presenceContext) {
681
- const state = {
682
- latestValues: makeLatestValues(props, context, presenceContext, scrapeMotionValuesFromProps),
683
- renderState: createRenderState(),
684
- };
685
- if (onUpdate) {
686
- /**
687
- * onMount works without the VisualElement because it could be
688
- * called before the VisualElement payload has been hydrated.
689
- * (e.g. if someone is using m components <m.circle />)
690
- */
691
- state.onMount = (instance) => onUpdate({ props, current: instance, ...state });
692
- state.onUpdate = (visualElement) => onUpdate(visualElement);
693
- }
694
- return state;
695
- }
696
- const makeUseVisualState = (config) => (props, isStatic) => {
697
- const context = react.useContext(MotionContext);
698
- const presenceContext = react.useContext(PresenceContext);
699
- const make = () => makeState(config, props, context, presenceContext);
700
- return isStatic ? make() : useConstant(make);
701
- };
702
- function makeLatestValues(props, context, presenceContext, scrapeMotionValues) {
703
- const values = {};
704
- const motionValues = scrapeMotionValues(props, {});
705
- for (const key in motionValues) {
706
- values[key] = resolveMotionValue(motionValues[key]);
707
- }
708
- let { initial, animate } = props;
709
- const isControllingVariants$1 = isControllingVariants(props);
710
- const isVariantNode$1 = isVariantNode(props);
711
- if (context &&
712
- isVariantNode$1 &&
713
- !isControllingVariants$1 &&
714
- props.inherit !== false) {
715
- if (initial === undefined)
716
- initial = context.initial;
717
- if (animate === undefined)
718
- animate = context.animate;
719
- }
720
- let isInitialAnimationBlocked = presenceContext
721
- ? presenceContext.initial === false
722
- : false;
723
- isInitialAnimationBlocked = isInitialAnimationBlocked || initial === false;
724
- const variantToSet = isInitialAnimationBlocked ? animate : initial;
725
- if (variantToSet &&
726
- typeof variantToSet !== "boolean" &&
727
- !isAnimationControls(variantToSet)) {
728
- const list = Array.isArray(variantToSet) ? variantToSet : [variantToSet];
729
- for (let i = 0; i < list.length; i++) {
730
- const resolved = resolveVariantFromProps(props, list[i]);
731
- if (resolved) {
732
- const { transitionEnd, transition, ...target } = resolved;
733
- for (const key in target) {
734
- let valueTarget = target[key];
735
- if (Array.isArray(valueTarget)) {
736
- /**
737
- * Take final keyframe if the initial animation is blocked because
738
- * we want to initialise at the end of that blocked animation.
739
- */
740
- const index = isInitialAnimationBlocked
741
- ? valueTarget.length - 1
742
- : 0;
743
- valueTarget = valueTarget[index];
744
- }
745
- if (valueTarget !== null) {
746
- values[key] = valueTarget;
747
- }
748
- }
749
- for (const key in transitionEnd) {
750
- values[key] = transitionEnd[key];
751
- }
752
- }
753
- }
754
- }
755
- return values;
756
- }
555
+ const scaleCorrectors = {};
757
556
 
758
557
  /**
759
558
  * Generate a list of every possible transform key.
@@ -782,9 +581,14 @@ const transformPropOrder = [
782
581
  */
783
582
  const transformProps = new Set(transformPropOrder);
784
583
 
785
- const checkStringStartsWith = (token) => (key) => typeof key === "string" && key.startsWith(token);
786
- const isCSSVariableName =
787
- /*@__PURE__*/ checkStringStartsWith("--");
584
+ function isForcedMotionValue(key, { layout, layoutId }) {
585
+ return (transformProps.has(key) ||
586
+ key.startsWith("origin") ||
587
+ ((layout || layoutId !== undefined) &&
588
+ (!!scaleCorrectors[key] || key === "opacity")));
589
+ }
590
+
591
+ const isMotionValue = (value) => Boolean(value && value.getVelocity);
788
592
 
789
593
  /**
790
594
  * Provided a value and a ValueType, returns the value as that value type.
@@ -1027,263 +831,12 @@ function buildHTMLStyles(state, latestValues, transformTemplate) {
1027
831
  }
1028
832
  }
1029
833
 
1030
- const dashKeys = {
1031
- offset: "stroke-dashoffset",
1032
- array: "stroke-dasharray",
1033
- };
1034
- const camelKeys = {
1035
- offset: "strokeDashoffset",
1036
- array: "strokeDasharray",
1037
- };
1038
- /**
1039
- * Build SVG path properties. Uses the path's measured length to convert
1040
- * our custom pathLength, pathSpacing and pathOffset into stroke-dashoffset
1041
- * and stroke-dasharray attributes.
1042
- *
1043
- * This function is mutative to reduce per-frame GC.
1044
- */
1045
- function buildSVGPath(attrs, length, spacing = 1, offset = 0, useDashCase = true) {
1046
- // Normalise path length by setting SVG attribute pathLength to 1
1047
- attrs.pathLength = 1;
1048
- // We use dash case when setting attributes directly to the DOM node and camel case
1049
- // when defining props on a React component.
1050
- const keys = useDashCase ? dashKeys : camelKeys;
1051
- // Build the dash offset
1052
- attrs[keys.offset] = px.transform(-offset);
1053
- // Build the dash array
1054
- const pathLength = px.transform(length);
1055
- const pathSpacing = px.transform(spacing);
1056
- attrs[keys.array] = `${pathLength} ${pathSpacing}`;
1057
- }
1058
-
1059
- function calcOrigin(origin, offset, size) {
1060
- return typeof origin === "string"
1061
- ? origin
1062
- : px.transform(offset + size * origin);
1063
- }
1064
- /**
1065
- * The SVG transform origin defaults are different to CSS and is less intuitive,
1066
- * so we use the measured dimensions of the SVG to reconcile these.
1067
- */
1068
- function calcSVGTransformOrigin(dimensions, originX, originY) {
1069
- const pxOriginX = calcOrigin(originX, dimensions.x, dimensions.width);
1070
- const pxOriginY = calcOrigin(originY, dimensions.y, dimensions.height);
1071
- return `${pxOriginX} ${pxOriginY}`;
1072
- }
1073
-
1074
- /**
1075
- * Build SVG visual attrbutes, like cx and style.transform
1076
- */
1077
- function buildSVGAttrs(state, { attrX, attrY, attrScale, originX, originY, pathLength, pathSpacing = 1, pathOffset = 0,
1078
- // This is object creation, which we try to avoid per-frame.
1079
- ...latest }, isSVGTag, transformTemplate) {
1080
- buildHTMLStyles(state, latest, transformTemplate);
1081
- /**
1082
- * For svg tags we just want to make sure viewBox is animatable and treat all the styles
1083
- * as normal HTML tags.
1084
- */
1085
- if (isSVGTag) {
1086
- if (state.style.viewBox) {
1087
- state.attrs.viewBox = state.style.viewBox;
1088
- }
1089
- return;
1090
- }
1091
- state.attrs = state.style;
1092
- state.style = {};
1093
- const { attrs, style, dimensions } = state;
1094
- /**
1095
- * However, we apply transforms as CSS transforms. So if we detect a transform we take it from attrs
1096
- * and copy it into style.
1097
- */
1098
- if (attrs.transform) {
1099
- if (dimensions)
1100
- style.transform = attrs.transform;
1101
- delete attrs.transform;
1102
- }
1103
- // Parse transformOrigin
1104
- if (dimensions &&
1105
- (originX !== undefined || originY !== undefined || style.transform)) {
1106
- style.transformOrigin = calcSVGTransformOrigin(dimensions, originX !== undefined ? originX : 0.5, originY !== undefined ? originY : 0.5);
1107
- }
1108
- // Render attrX/attrY/attrScale as attributes
1109
- if (attrX !== undefined)
1110
- attrs.x = attrX;
1111
- if (attrY !== undefined)
1112
- attrs.y = attrY;
1113
- if (attrScale !== undefined)
1114
- attrs.scale = attrScale;
1115
- // Build SVG path if one has been defined
1116
- if (pathLength !== undefined) {
1117
- buildSVGPath(attrs, pathLength, pathSpacing, pathOffset, false);
1118
- }
1119
- }
1120
-
1121
- const createHtmlRenderState = () => ({
1122
- style: {},
1123
- transform: {},
1124
- transformOrigin: {},
1125
- vars: {},
1126
- });
1127
-
1128
- const createSvgRenderState = () => ({
1129
- ...createHtmlRenderState(),
1130
- attrs: {},
1131
- });
1132
-
1133
- const isSVGTag = (tag) => typeof tag === "string" && tag.toLowerCase() === "svg";
1134
-
1135
- function renderHTML(element, { style, vars }, styleProp, projection) {
1136
- Object.assign(element.style, style, projection && projection.getProjectionStyles(styleProp));
1137
- // Loop over any CSS variables and assign those.
1138
- for (const key in vars) {
1139
- element.style.setProperty(key, vars[key]);
1140
- }
1141
- }
1142
-
1143
- /**
1144
- * A set of attribute names that are always read/written as camel case.
1145
- */
1146
- const camelCaseAttributes = new Set([
1147
- "baseFrequency",
1148
- "diffuseConstant",
1149
- "kernelMatrix",
1150
- "kernelUnitLength",
1151
- "keySplines",
1152
- "keyTimes",
1153
- "limitingConeAngle",
1154
- "markerHeight",
1155
- "markerWidth",
1156
- "numOctaves",
1157
- "targetX",
1158
- "targetY",
1159
- "surfaceScale",
1160
- "specularConstant",
1161
- "specularExponent",
1162
- "stdDeviation",
1163
- "tableValues",
1164
- "viewBox",
1165
- "gradientTransform",
1166
- "pathLength",
1167
- "startOffset",
1168
- "textLength",
1169
- "lengthAdjust",
1170
- ]);
1171
-
1172
- function renderSVG(element, renderState, _styleProp, projection) {
1173
- renderHTML(element, renderState, undefined, projection);
1174
- for (const key in renderState.attrs) {
1175
- element.setAttribute(!camelCaseAttributes.has(key) ? camelToDash(key) : key, renderState.attrs[key]);
1176
- }
1177
- }
1178
-
1179
- const scaleCorrectors = {};
1180
-
1181
- function isForcedMotionValue(key, { layout, layoutId }) {
1182
- return (transformProps.has(key) ||
1183
- key.startsWith("origin") ||
1184
- ((layout || layoutId !== undefined) &&
1185
- (!!scaleCorrectors[key] || key === "opacity")));
1186
- }
1187
-
1188
- function scrapeMotionValuesFromProps$1(props, prevProps, visualElement) {
1189
- var _a;
1190
- const { style } = props;
1191
- const newValues = {};
1192
- for (const key in style) {
1193
- if (isMotionValue(style[key]) ||
1194
- (prevProps.style &&
1195
- isMotionValue(prevProps.style[key])) ||
1196
- isForcedMotionValue(key, props) ||
1197
- ((_a = visualElement === null || visualElement === void 0 ? void 0 : visualElement.getValue(key)) === null || _a === void 0 ? void 0 : _a.liveStyle) !== undefined) {
1198
- newValues[key] = style[key];
1199
- }
1200
- }
1201
- return newValues;
1202
- }
1203
-
1204
- function scrapeMotionValuesFromProps(props, prevProps, visualElement) {
1205
- const newValues = scrapeMotionValuesFromProps$1(props, prevProps, visualElement);
1206
- for (const key in props) {
1207
- if (isMotionValue(props[key]) ||
1208
- isMotionValue(prevProps[key])) {
1209
- const targetKey = transformPropOrder.indexOf(key) !== -1
1210
- ? "attr" + key.charAt(0).toUpperCase() + key.substring(1)
1211
- : key;
1212
- newValues[targetKey] = props[key];
1213
- }
1214
- }
1215
- return newValues;
1216
- }
1217
-
1218
- function updateSVGDimensions(instance, renderState) {
1219
- try {
1220
- renderState.dimensions =
1221
- typeof instance.getBBox === "function"
1222
- ? instance.getBBox()
1223
- : instance.getBoundingClientRect();
1224
- }
1225
- catch (e) {
1226
- // Most likely trying to measure an unrendered element under Firefox
1227
- renderState.dimensions = {
1228
- x: 0,
1229
- y: 0,
1230
- width: 0,
1231
- height: 0,
1232
- };
1233
- }
1234
- }
1235
- const layoutProps = ["x", "y", "width", "height", "cx", "cy", "r"];
1236
- const svgMotionConfig = {
1237
- useVisualState: makeUseVisualState({
1238
- scrapeMotionValuesFromProps: scrapeMotionValuesFromProps,
1239
- createRenderState: createSvgRenderState,
1240
- onUpdate: ({ props, prevProps, current, renderState, latestValues, }) => {
1241
- if (!current)
1242
- return;
1243
- let hasTransform = !!props.drag;
1244
- if (!hasTransform) {
1245
- for (const key in latestValues) {
1246
- if (transformProps.has(key)) {
1247
- hasTransform = true;
1248
- break;
1249
- }
1250
- }
1251
- }
1252
- if (!hasTransform)
1253
- return;
1254
- let needsMeasure = !prevProps;
1255
- if (prevProps) {
1256
- /**
1257
- * Check the layout props for changes, if any are found we need to
1258
- * measure the element again.
1259
- */
1260
- for (let i = 0; i < layoutProps.length; i++) {
1261
- const key = layoutProps[i];
1262
- if (props[key] !==
1263
- prevProps[key]) {
1264
- needsMeasure = true;
1265
- }
1266
- }
1267
- }
1268
- if (!needsMeasure)
1269
- return;
1270
- frame.read(() => {
1271
- updateSVGDimensions(current, renderState);
1272
- frame.render(() => {
1273
- buildSVGAttrs(renderState, latestValues, isSVGTag(current.tagName), props.transformTemplate);
1274
- renderSVG(current, renderState);
1275
- });
1276
- });
1277
- },
1278
- }),
1279
- };
1280
-
1281
- const htmlMotionConfig = {
1282
- useVisualState: makeUseVisualState({
1283
- scrapeMotionValuesFromProps: scrapeMotionValuesFromProps$1,
1284
- createRenderState: createHtmlRenderState,
1285
- }),
1286
- };
834
+ const createHtmlRenderState = () => ({
835
+ style: {},
836
+ transform: {},
837
+ transformOrigin: {},
838
+ vars: {},
839
+ });
1287
840
 
1288
841
  function copyRawValuesOnly(target, source, props) {
1289
842
  for (const key in source) {
@@ -1447,35 +1000,192 @@ function filterProps(props, isDom, forwardMotionProps) {
1447
1000
  return filteredProps;
1448
1001
  }
1449
1002
 
1450
- function useSVGProps(props, visualState, _isStatic, Component) {
1451
- const visualProps = react.useMemo(() => {
1452
- const state = createSvgRenderState();
1453
- buildSVGAttrs(state, visualState, isSVGTag(Component), props.transformTemplate);
1454
- return {
1455
- ...state.attrs,
1456
- style: { ...state.style },
1457
- };
1458
- }, [visualState]);
1459
- if (props.style) {
1460
- const rawStyles = {};
1461
- copyRawValuesOnly(rawStyles, props.style, props);
1462
- visualProps.style = { ...rawStyles, ...visualProps.style };
1463
- }
1464
- return visualProps;
1465
- }
1466
-
1467
- function createUseRender(forwardMotionProps = false) {
1468
- const useRender = (Component, props, ref, { latestValues }, isStatic) => {
1469
- const useVisualProps = isSVGComponent(Component)
1470
- ? useSVGProps
1471
- : useHTMLProps;
1472
- const visualProps = useVisualProps(props, latestValues, isStatic, Component);
1473
- const filteredProps = filterProps(props, typeof Component === "string", forwardMotionProps);
1474
- const elementProps = Component !== react.Fragment
1475
- ? { ...filteredProps, ...visualProps, ref }
1476
- : {};
1477
- /**
1478
- * If component has been handed a motion value as its child,
1003
+ /**
1004
+ * We keep these listed separately as we use the lowercase tag names as part
1005
+ * of the runtime bundle to detect SVG components
1006
+ */
1007
+ const lowercaseSVGElements = [
1008
+ "animate",
1009
+ "circle",
1010
+ "defs",
1011
+ "desc",
1012
+ "ellipse",
1013
+ "g",
1014
+ "image",
1015
+ "line",
1016
+ "filter",
1017
+ "marker",
1018
+ "mask",
1019
+ "metadata",
1020
+ "path",
1021
+ "pattern",
1022
+ "polygon",
1023
+ "polyline",
1024
+ "rect",
1025
+ "stop",
1026
+ "switch",
1027
+ "symbol",
1028
+ "svg",
1029
+ "text",
1030
+ "tspan",
1031
+ "use",
1032
+ "view",
1033
+ ];
1034
+
1035
+ function isSVGComponent(Component) {
1036
+ if (
1037
+ /**
1038
+ * If it's not a string, it's a custom React component. Currently we only support
1039
+ * HTML custom React components.
1040
+ */
1041
+ typeof Component !== "string" ||
1042
+ /**
1043
+ * If it contains a dash, the element is a custom HTML webcomponent.
1044
+ */
1045
+ Component.includes("-")) {
1046
+ return false;
1047
+ }
1048
+ else if (
1049
+ /**
1050
+ * If it's in our list of lowercase SVG tags, it's an SVG component
1051
+ */
1052
+ lowercaseSVGElements.indexOf(Component) > -1 ||
1053
+ /**
1054
+ * If it contains a capital letter, it's an SVG component
1055
+ */
1056
+ /[A-Z]/u.test(Component)) {
1057
+ return true;
1058
+ }
1059
+ return false;
1060
+ }
1061
+
1062
+ const dashKeys = {
1063
+ offset: "stroke-dashoffset",
1064
+ array: "stroke-dasharray",
1065
+ };
1066
+ const camelKeys = {
1067
+ offset: "strokeDashoffset",
1068
+ array: "strokeDasharray",
1069
+ };
1070
+ /**
1071
+ * Build SVG path properties. Uses the path's measured length to convert
1072
+ * our custom pathLength, pathSpacing and pathOffset into stroke-dashoffset
1073
+ * and stroke-dasharray attributes.
1074
+ *
1075
+ * This function is mutative to reduce per-frame GC.
1076
+ */
1077
+ function buildSVGPath(attrs, length, spacing = 1, offset = 0, useDashCase = true) {
1078
+ // Normalise path length by setting SVG attribute pathLength to 1
1079
+ attrs.pathLength = 1;
1080
+ // We use dash case when setting attributes directly to the DOM node and camel case
1081
+ // when defining props on a React component.
1082
+ const keys = useDashCase ? dashKeys : camelKeys;
1083
+ // Build the dash offset
1084
+ attrs[keys.offset] = px.transform(-offset);
1085
+ // Build the dash array
1086
+ const pathLength = px.transform(length);
1087
+ const pathSpacing = px.transform(spacing);
1088
+ attrs[keys.array] = `${pathLength} ${pathSpacing}`;
1089
+ }
1090
+
1091
+ function calcOrigin(origin, offset, size) {
1092
+ return typeof origin === "string"
1093
+ ? origin
1094
+ : px.transform(offset + size * origin);
1095
+ }
1096
+ /**
1097
+ * The SVG transform origin defaults are different to CSS and is less intuitive,
1098
+ * so we use the measured dimensions of the SVG to reconcile these.
1099
+ */
1100
+ function calcSVGTransformOrigin(dimensions, originX, originY) {
1101
+ const pxOriginX = calcOrigin(originX, dimensions.x, dimensions.width);
1102
+ const pxOriginY = calcOrigin(originY, dimensions.y, dimensions.height);
1103
+ return `${pxOriginX} ${pxOriginY}`;
1104
+ }
1105
+
1106
+ /**
1107
+ * Build SVG visual attrbutes, like cx and style.transform
1108
+ */
1109
+ function buildSVGAttrs(state, { attrX, attrY, attrScale, originX, originY, pathLength, pathSpacing = 1, pathOffset = 0,
1110
+ // This is object creation, which we try to avoid per-frame.
1111
+ ...latest }, isSVGTag, transformTemplate) {
1112
+ buildHTMLStyles(state, latest, transformTemplate);
1113
+ /**
1114
+ * For svg tags we just want to make sure viewBox is animatable and treat all the styles
1115
+ * as normal HTML tags.
1116
+ */
1117
+ if (isSVGTag) {
1118
+ if (state.style.viewBox) {
1119
+ state.attrs.viewBox = state.style.viewBox;
1120
+ }
1121
+ return;
1122
+ }
1123
+ state.attrs = state.style;
1124
+ state.style = {};
1125
+ const { attrs, style, dimensions } = state;
1126
+ /**
1127
+ * However, we apply transforms as CSS transforms. So if we detect a transform we take it from attrs
1128
+ * and copy it into style.
1129
+ */
1130
+ if (attrs.transform) {
1131
+ if (dimensions)
1132
+ style.transform = attrs.transform;
1133
+ delete attrs.transform;
1134
+ }
1135
+ // Parse transformOrigin
1136
+ if (dimensions &&
1137
+ (originX !== undefined || originY !== undefined || style.transform)) {
1138
+ style.transformOrigin = calcSVGTransformOrigin(dimensions, originX !== undefined ? originX : 0.5, originY !== undefined ? originY : 0.5);
1139
+ }
1140
+ // Render attrX/attrY/attrScale as attributes
1141
+ if (attrX !== undefined)
1142
+ attrs.x = attrX;
1143
+ if (attrY !== undefined)
1144
+ attrs.y = attrY;
1145
+ if (attrScale !== undefined)
1146
+ attrs.scale = attrScale;
1147
+ // Build SVG path if one has been defined
1148
+ if (pathLength !== undefined) {
1149
+ buildSVGPath(attrs, pathLength, pathSpacing, pathOffset, false);
1150
+ }
1151
+ }
1152
+
1153
+ const createSvgRenderState = () => ({
1154
+ ...createHtmlRenderState(),
1155
+ attrs: {},
1156
+ });
1157
+
1158
+ const isSVGTag = (tag) => typeof tag === "string" && tag.toLowerCase() === "svg";
1159
+
1160
+ function useSVGProps(props, visualState, _isStatic, Component) {
1161
+ const visualProps = react.useMemo(() => {
1162
+ const state = createSvgRenderState();
1163
+ buildSVGAttrs(state, visualState, isSVGTag(Component), props.transformTemplate);
1164
+ return {
1165
+ ...state.attrs,
1166
+ style: { ...state.style },
1167
+ };
1168
+ }, [visualState]);
1169
+ if (props.style) {
1170
+ const rawStyles = {};
1171
+ copyRawValuesOnly(rawStyles, props.style, props);
1172
+ visualProps.style = { ...rawStyles, ...visualProps.style };
1173
+ }
1174
+ return visualProps;
1175
+ }
1176
+
1177
+ function createUseRender(forwardMotionProps = false) {
1178
+ const useRender = (Component, props, ref, { latestValues }, isStatic) => {
1179
+ const useVisualProps = isSVGComponent(Component)
1180
+ ? useSVGProps
1181
+ : useHTMLProps;
1182
+ const visualProps = useVisualProps(props, latestValues, isStatic, Component);
1183
+ const filteredProps = filterProps(props, typeof Component === "string", forwardMotionProps);
1184
+ const elementProps = Component !== react.Fragment
1185
+ ? { ...filteredProps, ...visualProps, ref }
1186
+ : {};
1187
+ /**
1188
+ * If component has been handed a motion value as its child,
1479
1189
  * memoise its initial value and render that. Subsequent updates
1480
1190
  * will be handled by the onChange handler
1481
1191
  */
@@ -1489,6 +1199,296 @@ function createUseRender(forwardMotionProps = false) {
1489
1199
  return useRender;
1490
1200
  }
1491
1201
 
1202
+ function getValueState(visualElement) {
1203
+ const state = [{}, {}];
1204
+ visualElement === null || visualElement === void 0 ? void 0 : visualElement.values.forEach((value, key) => {
1205
+ state[0][key] = value.get();
1206
+ state[1][key] = value.getVelocity();
1207
+ });
1208
+ return state;
1209
+ }
1210
+ function resolveVariantFromProps(props, definition, custom, visualElement) {
1211
+ /**
1212
+ * If the variant definition is a function, resolve.
1213
+ */
1214
+ if (typeof definition === "function") {
1215
+ const [current, velocity] = getValueState(visualElement);
1216
+ definition = definition(custom !== undefined ? custom : props.custom, current, velocity);
1217
+ }
1218
+ /**
1219
+ * If the variant definition is a variant label, or
1220
+ * the function returned a variant label, resolve.
1221
+ */
1222
+ if (typeof definition === "string") {
1223
+ definition = props.variants && props.variants[definition];
1224
+ }
1225
+ /**
1226
+ * At this point we've resolved both functions and variant labels,
1227
+ * but the resolved variant label might itself have been a function.
1228
+ * If so, resolve. This can only have returned a valid target object.
1229
+ */
1230
+ if (typeof definition === "function") {
1231
+ const [current, velocity] = getValueState(visualElement);
1232
+ definition = definition(custom !== undefined ? custom : props.custom, current, velocity);
1233
+ }
1234
+ return definition;
1235
+ }
1236
+
1237
+ /**
1238
+ * Creates a constant value over the lifecycle of a component.
1239
+ *
1240
+ * Even if `useMemo` is provided an empty array as its final argument, it doesn't offer
1241
+ * a guarantee that it won't re-run for performance reasons later on. By using `useConstant`
1242
+ * you can ensure that initialisers don't execute twice or more.
1243
+ */
1244
+ function useConstant(init) {
1245
+ const ref = react.useRef(null);
1246
+ if (ref.current === null) {
1247
+ ref.current = init();
1248
+ }
1249
+ return ref.current;
1250
+ }
1251
+
1252
+ const isCustomValue = (v) => {
1253
+ return Boolean(v && typeof v === "object" && v.mix && v.toValue);
1254
+ };
1255
+
1256
+ /**
1257
+ * If the provided value is a MotionValue, this returns the actual value, otherwise just the value itself
1258
+ *
1259
+ * TODO: Remove and move to library
1260
+ */
1261
+ function resolveMotionValue(value) {
1262
+ const unwrappedValue = isMotionValue(value) ? value.get() : value;
1263
+ return isCustomValue(unwrappedValue)
1264
+ ? unwrappedValue.toValue()
1265
+ : unwrappedValue;
1266
+ }
1267
+
1268
+ function makeState({ scrapeMotionValuesFromProps, createRenderState, onUpdate, }, props, context, presenceContext) {
1269
+ const state = {
1270
+ latestValues: makeLatestValues(props, context, presenceContext, scrapeMotionValuesFromProps),
1271
+ renderState: createRenderState(),
1272
+ };
1273
+ if (onUpdate) {
1274
+ /**
1275
+ * onMount works without the VisualElement because it could be
1276
+ * called before the VisualElement payload has been hydrated.
1277
+ * (e.g. if someone is using m components <m.circle />)
1278
+ */
1279
+ state.onMount = (instance) => onUpdate({ props, current: instance, ...state });
1280
+ state.onUpdate = (visualElement) => onUpdate(visualElement);
1281
+ }
1282
+ return state;
1283
+ }
1284
+ const makeUseVisualState = (config) => (props, isStatic) => {
1285
+ const context = react.useContext(MotionContext);
1286
+ const presenceContext = react.useContext(PresenceContext);
1287
+ const make = () => makeState(config, props, context, presenceContext);
1288
+ return isStatic ? make() : useConstant(make);
1289
+ };
1290
+ function makeLatestValues(props, context, presenceContext, scrapeMotionValues) {
1291
+ const values = {};
1292
+ const motionValues = scrapeMotionValues(props, {});
1293
+ for (const key in motionValues) {
1294
+ values[key] = resolveMotionValue(motionValues[key]);
1295
+ }
1296
+ let { initial, animate } = props;
1297
+ const isControllingVariants$1 = isControllingVariants(props);
1298
+ const isVariantNode$1 = isVariantNode(props);
1299
+ if (context &&
1300
+ isVariantNode$1 &&
1301
+ !isControllingVariants$1 &&
1302
+ props.inherit !== false) {
1303
+ if (initial === undefined)
1304
+ initial = context.initial;
1305
+ if (animate === undefined)
1306
+ animate = context.animate;
1307
+ }
1308
+ let isInitialAnimationBlocked = presenceContext
1309
+ ? presenceContext.initial === false
1310
+ : false;
1311
+ isInitialAnimationBlocked = isInitialAnimationBlocked || initial === false;
1312
+ const variantToSet = isInitialAnimationBlocked ? animate : initial;
1313
+ if (variantToSet &&
1314
+ typeof variantToSet !== "boolean" &&
1315
+ !isAnimationControls(variantToSet)) {
1316
+ const list = Array.isArray(variantToSet) ? variantToSet : [variantToSet];
1317
+ for (let i = 0; i < list.length; i++) {
1318
+ const resolved = resolveVariantFromProps(props, list[i]);
1319
+ if (resolved) {
1320
+ const { transitionEnd, transition, ...target } = resolved;
1321
+ for (const key in target) {
1322
+ let valueTarget = target[key];
1323
+ if (Array.isArray(valueTarget)) {
1324
+ /**
1325
+ * Take final keyframe if the initial animation is blocked because
1326
+ * we want to initialise at the end of that blocked animation.
1327
+ */
1328
+ const index = isInitialAnimationBlocked
1329
+ ? valueTarget.length - 1
1330
+ : 0;
1331
+ valueTarget = valueTarget[index];
1332
+ }
1333
+ if (valueTarget !== null) {
1334
+ values[key] = valueTarget;
1335
+ }
1336
+ }
1337
+ for (const key in transitionEnd) {
1338
+ values[key] = transitionEnd[key];
1339
+ }
1340
+ }
1341
+ }
1342
+ }
1343
+ return values;
1344
+ }
1345
+
1346
+ function scrapeMotionValuesFromProps$1(props, prevProps, visualElement) {
1347
+ var _a;
1348
+ const { style } = props;
1349
+ const newValues = {};
1350
+ for (const key in style) {
1351
+ if (isMotionValue(style[key]) ||
1352
+ (prevProps.style &&
1353
+ isMotionValue(prevProps.style[key])) ||
1354
+ isForcedMotionValue(key, props) ||
1355
+ ((_a = visualElement === null || visualElement === void 0 ? void 0 : visualElement.getValue(key)) === null || _a === void 0 ? void 0 : _a.liveStyle) !== undefined) {
1356
+ newValues[key] = style[key];
1357
+ }
1358
+ }
1359
+ return newValues;
1360
+ }
1361
+
1362
+ const htmlMotionConfig = {
1363
+ useVisualState: makeUseVisualState({
1364
+ scrapeMotionValuesFromProps: scrapeMotionValuesFromProps$1,
1365
+ createRenderState: createHtmlRenderState,
1366
+ }),
1367
+ };
1368
+
1369
+ const { schedule: frame, cancel: cancelFrame, state: frameData, steps: frameSteps, } = createRenderBatcher(typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : noop, true);
1370
+
1371
+ function renderHTML(element, { style, vars }, styleProp, projection) {
1372
+ Object.assign(element.style, style, projection && projection.getProjectionStyles(styleProp));
1373
+ // Loop over any CSS variables and assign those.
1374
+ for (const key in vars) {
1375
+ element.style.setProperty(key, vars[key]);
1376
+ }
1377
+ }
1378
+
1379
+ /**
1380
+ * A set of attribute names that are always read/written as camel case.
1381
+ */
1382
+ const camelCaseAttributes = new Set([
1383
+ "baseFrequency",
1384
+ "diffuseConstant",
1385
+ "kernelMatrix",
1386
+ "kernelUnitLength",
1387
+ "keySplines",
1388
+ "keyTimes",
1389
+ "limitingConeAngle",
1390
+ "markerHeight",
1391
+ "markerWidth",
1392
+ "numOctaves",
1393
+ "targetX",
1394
+ "targetY",
1395
+ "surfaceScale",
1396
+ "specularConstant",
1397
+ "specularExponent",
1398
+ "stdDeviation",
1399
+ "tableValues",
1400
+ "viewBox",
1401
+ "gradientTransform",
1402
+ "pathLength",
1403
+ "startOffset",
1404
+ "textLength",
1405
+ "lengthAdjust",
1406
+ ]);
1407
+
1408
+ function renderSVG(element, renderState, _styleProp, projection) {
1409
+ renderHTML(element, renderState, undefined, projection);
1410
+ for (const key in renderState.attrs) {
1411
+ element.setAttribute(!camelCaseAttributes.has(key) ? camelToDash(key) : key, renderState.attrs[key]);
1412
+ }
1413
+ }
1414
+
1415
+ function scrapeMotionValuesFromProps(props, prevProps, visualElement) {
1416
+ const newValues = scrapeMotionValuesFromProps$1(props, prevProps, visualElement);
1417
+ for (const key in props) {
1418
+ if (isMotionValue(props[key]) ||
1419
+ isMotionValue(prevProps[key])) {
1420
+ const targetKey = transformPropOrder.indexOf(key) !== -1
1421
+ ? "attr" + key.charAt(0).toUpperCase() + key.substring(1)
1422
+ : key;
1423
+ newValues[targetKey] = props[key];
1424
+ }
1425
+ }
1426
+ return newValues;
1427
+ }
1428
+
1429
+ function updateSVGDimensions(instance, renderState) {
1430
+ try {
1431
+ renderState.dimensions =
1432
+ typeof instance.getBBox === "function"
1433
+ ? instance.getBBox()
1434
+ : instance.getBoundingClientRect();
1435
+ }
1436
+ catch (e) {
1437
+ // Most likely trying to measure an unrendered element under Firefox
1438
+ renderState.dimensions = {
1439
+ x: 0,
1440
+ y: 0,
1441
+ width: 0,
1442
+ height: 0,
1443
+ };
1444
+ }
1445
+ }
1446
+ const layoutProps = ["x", "y", "width", "height", "cx", "cy", "r"];
1447
+ const svgMotionConfig = {
1448
+ useVisualState: makeUseVisualState({
1449
+ scrapeMotionValuesFromProps: scrapeMotionValuesFromProps,
1450
+ createRenderState: createSvgRenderState,
1451
+ onUpdate: ({ props, prevProps, current, renderState, latestValues, }) => {
1452
+ if (!current)
1453
+ return;
1454
+ let hasTransform = !!props.drag;
1455
+ if (!hasTransform) {
1456
+ for (const key in latestValues) {
1457
+ if (transformProps.has(key)) {
1458
+ hasTransform = true;
1459
+ break;
1460
+ }
1461
+ }
1462
+ }
1463
+ if (!hasTransform)
1464
+ return;
1465
+ let needsMeasure = !prevProps;
1466
+ if (prevProps) {
1467
+ /**
1468
+ * Check the layout props for changes, if any are found we need to
1469
+ * measure the element again.
1470
+ */
1471
+ for (let i = 0; i < layoutProps.length; i++) {
1472
+ const key = layoutProps[i];
1473
+ if (props[key] !==
1474
+ prevProps[key]) {
1475
+ needsMeasure = true;
1476
+ }
1477
+ }
1478
+ }
1479
+ if (!needsMeasure)
1480
+ return;
1481
+ frame.read(() => {
1482
+ updateSVGDimensions(current, renderState);
1483
+ frame.render(() => {
1484
+ buildSVGAttrs(renderState, latestValues, isSVGTag(current.tagName), props.transformTemplate);
1485
+ renderSVG(current, renderState);
1486
+ });
1487
+ });
1488
+ },
1489
+ }),
1490
+ };
1491
+
1492
1492
  function createMotionComponentFactory(preloadedFeatures, createVisualElement) {
1493
1493
  return function createMotionComponent(Component, { forwardMotionProps } = { forwardMotionProps: false }) {
1494
1494
  const baseConfig = isSVGComponent(Component)