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") {