diff --git a/dev/benchmarks/mix-unit-value-framer-motion.html b/dev/benchmarks/mix-unit-value-framer-motion.html
index aff0ac6c41..92e8192461 100644
--- a/dev/benchmarks/mix-unit-value-framer-motion.html
+++ b/dev/benchmarks/mix-unit-value-framer-motion.html
@@ -35,17 +35,18 @@
diff --git a/dev/benchmarks/mix-unit-value-greensock.html b/dev/benchmarks/mix-unit-value-greensock.html
index fba2566380..f45f54cfd3 100644
--- a/dev/benchmarks/mix-unit-value-greensock.html
+++ b/dev/benchmarks/mix-unit-value-greensock.html
@@ -37,12 +37,15 @@
/**
* Create an interpolate function that mixes unit values.
*/
- const px = gsap.utils.interpolate("0px", "100px")
+ const px = gsap.utils.interpolate(
+ "var(--test-1, 1) 10px",
+ "var(--test-9, 3) 60px"
+ )
- const numRuns = 1000000
+ const numRuns = 10
let startTime = performance.now()
for (let i = 0; i < numRuns; i++) {
- px(i / numRuns)
+ console.log(px(i / numRuns))
}
console.log(`First run: ${performance.now() - startTime}ms`)
diff --git a/packages/framer-motion/src/render/dom/utils/is-css-variable.ts b/packages/framer-motion/src/render/dom/utils/is-css-variable.ts
index 8147288804..8cb1c80e8c 100644
--- a/packages/framer-motion/src/render/dom/utils/is-css-variable.ts
+++ b/packages/framer-motion/src/render/dom/utils/is-css-variable.ts
@@ -8,8 +8,12 @@ const checkStringStartsWith =
typeof key === "string" && key.startsWith(token)
export const isCSSVariableName = checkStringStartsWith("--")
-export const isCSSVariableToken =
- checkStringStartsWith("var(--")
+
+const startsAsVariableToken = checkStringStartsWith("var(--")
+export const isCSSVariableToken = (key?: string): key is CSSVariableToken =>
+ startsAsVariableToken(key) && singleCssVariableRegex.test(key)
export const cssVariableRegex =
/var\s*\(\s*--[\w-]+(\s*,\s*(?:(?:[^)(]|\((?:[^)(]+|\([^)(]*\))*\))*)+)?\s*\)/g
+const singleCssVariableRegex =
+ /var\s*\(\s*--[\w-]+(\s*,\s*(?:(?:[^)(]|\((?:[^)(]+|\([^)(]*\))*\))*)+)?\s*\)$/i
diff --git a/packages/framer-motion/src/utils/mix/__tests__/index.test.ts b/packages/framer-motion/src/utils/mix/__tests__/index.test.ts
index 35f7772322..cd19cf0e9d 100644
--- a/packages/framer-motion/src/utils/mix/__tests__/index.test.ts
+++ b/packages/framer-motion/src/utils/mix/__tests__/index.test.ts
@@ -28,4 +28,13 @@ describe("mix", () => {
expect(mixer(0.5)).toEqual([[1, 2], { c: 0.5, d: "1.5px" }])
})
+
+ test("mixes complex values", () => {
+ expect(mix("var(--test) 0px", "var(--test) 20px")(0.5)).toBe(
+ "var(--test) 10px"
+ )
+ expect(mix("var(--test-1) 10px", "var(--test-9) 60px")(0.5)).toBe(
+ "var(--test-9) 35px"
+ )
+ })
})
diff --git a/packages/framer-motion/src/utils/mix/__tests__/mix-complex.test.ts b/packages/framer-motion/src/utils/mix/__tests__/mix-complex.test.ts
index 077b23c6c6..cf30bffb6b 100644
--- a/packages/framer-motion/src/utils/mix/__tests__/mix-complex.test.ts
+++ b/packages/framer-motion/src/utils/mix/__tests__/mix-complex.test.ts
@@ -26,6 +26,15 @@ test("mixComplex errors", () => {
)
})
+test("mixComplex mixes var() and unit types", () => {
+ expect(mixComplex("var(--test) 0px", "var(--test) 20px")(0.5)).toBe(
+ "var(--test) 10px"
+ )
+ expect(mixComplex("var(--test-1) 10px", "var(--test-9) 60px")(0.5)).toBe(
+ "var(--test-9) 35px"
+ )
+})
+
test("mixComplex can interpolate out-of-order values", () => {
expect(mixComplex("#fff 0px 0px", "20px 0px #000")(0.5)).toBe(
"10px 0px rgba(180, 180, 180, 1)"
diff --git a/packages/framer-motion/src/utils/mix/complex.ts b/packages/framer-motion/src/utils/mix/complex.ts
index 850fd429b0..29d7c658a0 100644
--- a/packages/framer-motion/src/utils/mix/complex.ts
+++ b/packages/framer-motion/src/utils/mix/complex.ts
@@ -10,6 +10,7 @@ import {
analyseComplexValue,
complex,
} from "../../value/types/complex"
+import { isCSSVariableToken } from "../../render/dom/utils/is-css-variable"
type MixableArray = Array
type MixableObject = {
@@ -28,12 +29,11 @@ export function getMixer(a: T) {
if (typeof a === "number") {
return mixNumber
} else if (typeof a === "string") {
- if (a.startsWith("var(")) {
- return mixImmediate
- } else if (color.test(a)) {
- return mixColor
- }
- return mixComplex
+ return isCSSVariableToken(a)
+ ? mixImmediate
+ : color.test(a)
+ ? mixColor
+ : mixComplex
} else if (Array.isArray(a)) {
return mixArray
} else if (typeof a === "object") {