Skip to content

Commit

Permalink
Resolving numerical CSS variables
Browse files Browse the repository at this point in the history
  • Loading branch information
mattgperry committed Aug 11, 2023
1 parent c938fd9 commit 19716af
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 2 deletions.
34 changes: 34 additions & 0 deletions dev/examples/Animation-batch-read-writes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import * as React from "react"
import { motion } from "framer-motion"

/**
* An example of the Motion keyframes syntax.
*/

const style = {
width: 100,
height: 100,
backgroundColor: "#f00",
x: 0,
borderRadius: 20,
color: "rgba(0,0,0,0)",
}

export const App = () => {
return (
<div style={{ "--a": "#00F", "--b": 360, "--c": 100 } as any}>
<motion.div
animate={{
backgroundColor: "var(--a)",
rotateX: "var(--b)",
x: "var(--c)",
y: "var(--c)",
}}
style={style}
onUpdate={console.log}
>
a
</motion.div>
</div>
)
}
40 changes: 40 additions & 0 deletions dev/tests/css-var-numbers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as React from "react"
import { motion, useMotionValue } from "framer-motion"

/**
* An example of the Motion keyframes syntax.
*/

const style = {
width: 100,
height: 100,
backgroundColor: "#f00",
x: 0,
borderRadius: 20,
}
let isFirstFrame = true
export const App = () => {
const content = useMotionValue("")

return (
<div style={{ "--a": "#00F", "--b": "360deg", "--c": 2 } as any}>
<motion.div
animate={{
originX: 0,
originY: 0,
backgroundColor: "var(--a)",
scale: "var(--c)",
}}
style={style}
onUpdate={({ scale }) => {
if (isFirstFrame) {
content.set(scale === "2" ? "Fail" : "Success")
}
isFirstFrame = false
}}
>
{content}
</motion.div>
</div>
)
}
13 changes: 13 additions & 0 deletions packages/framer-motion/cypress/integration/css-var-numbers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
describe("animate() x layout prop timing", () => {
it("animate() plays as expected when layout prop is present", () => {
cy.visit("?test=animate-layout-timing")
.wait(1000)
.get("#action")
.trigger("click", 1, 1, { force: true })
.wait(600)
.get("#result")
.should(([$element]: any) => {
expect($element.value).to.equal("Success")
})
})
})
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Target, TargetWithKeyframes } from "../../../types"
import { invariant } from "../../../utils/errors"
import { isNumericalString } from "../../../utils/is-numerical-string"
import type { VisualElement } from "../../VisualElement"
import { isCSSVariableToken, CSSVariableToken } from "./is-css-variable"

Expand Down Expand Up @@ -27,7 +28,7 @@ function getVariableValue(
current: CSSVariableToken,
element: Element,
depth = 1
): string | undefined {
): string | number | undefined {
invariant(
depth <= maxDepth,
`Max CSS variable fallback depth detected in property "${current}". This may indicate a circular fallback dependency.`
Expand All @@ -42,7 +43,8 @@ function getVariableValue(
const resolved = window.getComputedStyle(element).getPropertyValue(token)

if (resolved) {
return resolved.trim()
const trimmed = resolved.trim()
return isNumericalString(trimmed) ? parseFloat(trimmed) : trimmed
} else if (isCSSVariableToken(fallback)) {
// The fallback might itself be a CSS variable, in which case we attempt to resolve it too.
return getVariableValue(fallback, element, depth + 1)
Expand Down Expand Up @@ -86,6 +88,7 @@ export function resolveCSSVariables(
if (!isCSSVariableToken(current)) continue

const resolved = getVariableValue(current, element)

if (!resolved) continue

// Clone target if it hasn't already been
Expand Down

0 comments on commit 19716af

Please sign in to comment.