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.
- package/dist/cjs/index.js +43 -12
- package/dist/cjs/react-client.js +504 -486
- package/dist/cjs/react-m.js +494 -494
- package/dist/es/framer-motion/dist/es/components/AnimatePresence/index.mjs +1 -1
- package/dist/es/framer-motion/dist/es/projection/node/create-projection-node.mjs +6 -1
- package/dist/es/framer-motion/dist/es/render/VisualElement.mjs +3 -0
- package/dist/es/framer-motion/dist/es/render/components/create-factory.mjs +2 -2
- package/dist/es/framer-motion/dist/es/render/svg/SVGVisualElement.mjs +12 -0
- package/dist/es/framer-motion/dist/es/render/svg/config-motion.mjs +1 -1
- package/dist/es/framer-motion/dist/es/render/utils/motion-values.mjs +1 -1
- package/dist/es/framer-motion/dist/es/value/index.mjs +1 -1
- package/dist/motion.dev.js +43 -12
- package/dist/motion.js +1 -1
- package/package.json +3 -3
package/dist/cjs/react-m.js
CHANGED
|
@@ -548,212 +548,11 @@ function getProjectionFunctionality(props) {
|
|
|
548
548
|
};
|
|
549
549
|
}
|
|
550
550
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
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
|
-
|
|
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
|
-
|
|
786
|
-
|
|
787
|
-
|
|
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
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1035
|
-
|
|
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
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
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)
|