From bfece69ac734b364fbfd33ed855ecf354ce037d1 Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Tue, 23 Nov 2021 13:36:49 +0000 Subject: [PATCH 1/2] 5.3.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ee517b05f..4a0924c64 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "framer-motion", - "version": "5.3.1", + "version": "5.3.2", "description": "A simple and powerful React animation library", "main": "dist/framer-motion.cjs.js", "module": "dist/es/index.mjs", From a68a72f064f4d2019ef0047f001c024fd0fe0169 Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Tue, 23 Nov 2021 14:31:16 +0000 Subject: [PATCH 2/2] Fixing animating to CSS variables with SVG elements --- CHANGELOG.md | 6 ++ cypress/integration/svg.ts | 62 ++++++++----------- dev/tests/svg-css-vars.tsx | 29 +++++++++ .../dom/utils/css-variables-conversion.ts | 7 ++- 4 files changed, 65 insertions(+), 39 deletions(-) create mode 100644 dev/tests/svg-css-vars.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index e7668a06a..0bd541848 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ Framer Motion adheres to [Semantic Versioning](http://semver.org/). +## [5.3.3] 2021-11-Unreleased + +### Fixed + +- Fixing animating to CSS variables with `SVGElement`. [Issue](https://github.com/framer/motion/issues/1334) + ## [5.3.2] 2021-11-23 ### Fixed diff --git a/cypress/integration/svg.ts b/cypress/integration/svg.ts index 24b87e510..7b7a49657 100644 --- a/cypress/integration/svg.ts +++ b/cypress/integration/svg.ts @@ -5,12 +5,8 @@ describe("SVG", () => { .get("[data-testid='rotate']") .should(($rotate: any) => { const rotate = $rotate[0] as SVGRectElement - const { - top, - left, - right, - bottom, - } = rotate.getBoundingClientRect() + const { top, left, right, bottom } = + rotate.getBoundingClientRect() expect(Math.round(top)).to.equal(29) expect(Math.round(left)).to.equal(29) expect(Math.round(right)).to.equal(171) @@ -19,12 +15,8 @@ describe("SVG", () => { .get("[data-testid='scale']") .should(($scale: any) => { const scale = $scale[0] as SVGRectElement - const { - top, - left, - right, - bottom, - } = scale.getBoundingClientRect() + const { top, left, right, bottom } = + scale.getBoundingClientRect() expect(top).to.equal(150) expect(left).to.equal(0) expect(right).to.equal(200) @@ -33,12 +25,8 @@ describe("SVG", () => { .get("[data-testid='translate']") .should(($translate: any) => { const translate = $translate[0] as SVGRectElement - const { - top, - left, - right, - bottom, - } = translate.getBoundingClientRect() + const { top, left, right, bottom } = + translate.getBoundingClientRect() expect(top).to.equal(350) expect(left).to.equal(150) expect(right).to.equal(250) @@ -51,12 +39,8 @@ describe("SVG", () => { .get("[data-testid='rotate']") .should(($rotate: any) => { const rotate = $rotate[0] as SVGRectElement - const { - top, - left, - right, - bottom, - } = rotate.getBoundingClientRect() + const { top, left, right, bottom } = + rotate.getBoundingClientRect() expect(Math.round(top)).to.equal(29) expect(Math.round(left)).to.equal(29) expect(Math.round(right)).to.equal(171) @@ -65,12 +49,8 @@ describe("SVG", () => { .get("[data-testid='scale']") .should(($scale: any) => { const scale = $scale[0] as SVGRectElement - const { - top, - left, - right, - bottom, - } = scale.getBoundingClientRect() + const { top, left, right, bottom } = + scale.getBoundingClientRect() expect(top).to.equal(150) expect(left).to.equal(0) expect(right).to.equal(200) @@ -79,16 +59,26 @@ describe("SVG", () => { .get("[data-testid='translate']") .should(($translate: any) => { const translate = $translate[0] as SVGRectElement - const { - top, - left, - right, - bottom, - } = translate.getBoundingClientRect() + const { top, left, right, bottom } = + translate.getBoundingClientRect() expect(top).to.equal(350) expect(left).to.equal(150) expect(right).to.equal(250) expect(bottom).to.equal(450) }) }) + + it("Correctly animates to CSS variables", () => { + cy.visit("?test=svg-css-vars") + .wait(50) + .get("svg") + .click() + .wait(50) + .get("circle") + .should(([$circle]: any) => { + expect($circle.getAttribute("fill")).to.equal( + "rgba(180, 0, 180, 1)" + ) + }) + }) }) diff --git a/dev/tests/svg-css-vars.tsx b/dev/tests/svg-css-vars.tsx new file mode 100644 index 000000000..66a718516 --- /dev/null +++ b/dev/tests/svg-css-vars.tsx @@ -0,0 +1,29 @@ +import * as React from "react" +import { motion } from "@framer" + +/** + * An example of providing a MotionValue to an SVG component via its props + */ + +export const App = () => { + const [state, setState] = React.useState(false) + return ( + setState(!state)} + style={{ "--color": "#f00" } as any} + > + 0.5 }} + /> + + ) +} diff --git a/src/render/dom/utils/css-variables-conversion.ts b/src/render/dom/utils/css-variables-conversion.ts index 28b2c759a..b57300b2a 100644 --- a/src/render/dom/utils/css-variables-conversion.ts +++ b/src/render/dom/utils/css-variables-conversion.ts @@ -15,7 +15,8 @@ function isCSSVariable(value: any): value is string { * * @param current */ -export const cssVariableRegex = /var\((--[a-zA-Z0-9-_]+),? ?([a-zA-Z0-9 ()%#.,-]+)?\)/ +export const cssVariableRegex = + /var\((--[a-zA-Z0-9-_]+),? ?([a-zA-Z0-9 ()%#.,-]+)?\)/ export function parseCSSVariable(current: string) { const match = cssVariableRegex.exec(current) if (!match) return [,] @@ -27,7 +28,7 @@ export function parseCSSVariable(current: string) { const maxDepth = 4 function getVariableValue( current: string, - element: HTMLElement, + element: Element, depth = 1 ): string | undefined { invariant( @@ -64,7 +65,7 @@ export function resolveCSSVariables( transitionEnd: Target | undefined ): { target: TargetWithKeyframes; transitionEnd?: Target } { const element = visualElement.getInstance() - if (!(element instanceof HTMLElement)) return { target, transitionEnd } + if (!(element instanceof Element)) return { target, transitionEnd } // If `transitionEnd` isn't `undefined`, clone it. We could clone `target` and `transitionEnd` // only if they change but I think this reads clearer and this isn't a performance-critical path.