diff --git a/CHANGELOG.md b/CHANGELOG.md index 4acb6e789d..b86b2c3469 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ Framer Motion adheres to [Semantic Versioning](http://semver.org/). +## [5.5.8] 2022-01-12 + +### Fixed + +- Removing `transformTemplate` prop correctly rerenders element. + ## [5.5.7] 2022-01-11 ### Fixed diff --git a/src/motion/__tests__/component.test.tsx b/src/motion/__tests__/component.test.tsx index 296a9a0456..0f23badd8c 100644 --- a/src/motion/__tests__/component.test.tsx +++ b/src/motion/__tests__/component.test.tsx @@ -257,20 +257,6 @@ describe("motion component rendering and styles", () => { expect(container.firstChild).toHaveStyle("background-color: #f00") }) - it("applies transformTemplate on initial render", () => { - const { container } = render( - - `translateY(${x}) ${generated}` - } - /> - ) - expect(container.firstChild).toHaveStyle( - "transform: translateY(10px) translateX(10px) translateZ(0)" - ) - }) - it("renders transform", () => { const { container } = render( @@ -278,47 +264,6 @@ describe("motion component rendering and styles", () => { expect(container.firstChild).toHaveStyle("transform: translateX(10px)") }) - it("applies updated transformTemplate", () => { - const { container, rerender } = render( - - `translateY(${x}) ${generated}` - } - /> - ) - expect(container.firstChild).toHaveStyle( - "transform: translateY(10px) translateX(10px) translateZ(0)" - ) - - rerender( - { - const newX = typeof x === "string" ? parseFloat(x) : x - return `translateY(${(newX as number) * 2}px) ${generated}` - }} - /> - ) - expect(container.firstChild).toHaveStyle( - "transform: translateY(20px) translateX(10px) translateZ(0)" - ) - }) - - it("renders transform with transformTemplate", () => { - const { container } = render( - - `translateY(20px) ${generated}` - } - style={{ x: 10 }} - /> - ) - expect(container.firstChild).toHaveStyle( - "transform: translateY(20px) translateX(10px) translateZ(0)" - ) - }) - it("filters MotionProps from the DOM", () => { const { container } = render() expect(container.firstChild).not.toHaveAttribute("initial") diff --git a/src/motion/__tests__/transformTemplate.test.tsx b/src/motion/__tests__/transformTemplate.test.tsx new file mode 100644 index 0000000000..1d581c504c --- /dev/null +++ b/src/motion/__tests__/transformTemplate.test.tsx @@ -0,0 +1,114 @@ +import { render } from "../../../jest.setup" +import { motion } from "../../" +import * as React from "react" +import sync from "framesync" + +describe("transformTemplate", () => { + it("applies transformTemplate on initial render", () => { + const { container } = render( + + `translateY(${x}) ${generated}` + } + /> + ) + expect(container.firstChild).toHaveStyle( + "transform: translateY(10px) translateX(10px) translateZ(0)" + ) + }) + + it("applies updated transformTemplate", () => { + const { container, rerender } = render( + + `translateY(${x}) ${generated}` + } + /> + ) + expect(container.firstChild).toHaveStyle( + "transform: translateY(10px) translateX(10px) translateZ(0)" + ) + + rerender( + { + const newX = typeof x === "string" ? parseFloat(x) : x + return `translateY(${(newX as number) * 2}px) ${generated}` + }} + /> + ) + expect(container.firstChild).toHaveStyle( + "transform: translateY(20px) translateX(10px) translateZ(0)" + ) + }) + + it("renders transform with transformTemplate", () => { + const { container } = render( + + `translateY(20px) ${generated}` + } + style={{ x: 10 }} + /> + ) + expect(container.firstChild).toHaveStyle( + "transform: translateY(20px) translateX(10px) translateZ(0)" + ) + }) + + it("renders transformTemplate without any transform", () => { + const { container } = render( + `translateY(20px)`} /> + ) + expect(container.firstChild).toHaveStyle("transform: translateY(20px)") + }) + + it("removes transformTemplate if prop is removed and transform is changed", async () => { + const { container, rerender } = render( + `translateY(20px)`} + style={{ x: 10 }} + /> + ) + expect(container.firstChild).toHaveStyle("transform: translateY(20px)") + rerender() + + await new Promise((resolve) => sync.postRender(resolve)) + + expect(container.firstChild).toHaveStyle( + "transform: translateX(20px) translateZ(0)" + ) + }) + + it("removes transformTemplate if prop is removed and transform is not changed", async () => { + const { container, rerender } = render( + `translateY(20px)`} + style={{ x: 10 }} + /> + ) + expect(container.firstChild).toHaveStyle("transform: translateY(20px)") + rerender() + + await new Promise((resolve) => sync.postRender(resolve)) + + expect(container.firstChild).toHaveStyle( + "transform: translateX(10px) translateZ(0)" + ) + }) + + it("removes transformTemplate if prop is removed", async () => { + const { container, rerender } = render( + `translateY(20px)`} /> + ) + expect(container.firstChild).toHaveStyle("transform: translateY(20px)") + rerender() + + await new Promise((resolve) => sync.postRender(resolve)) + + expect(container.firstChild).toHaveStyle("transform: none") + }) +}) diff --git a/src/render/html/utils/build-styles.ts b/src/render/html/utils/build-styles.ts index 60026d9757..7b0f270633 100644 --- a/src/render/html/utils/build-styles.ts +++ b/src/render/html/utils/build-styles.ts @@ -79,6 +79,8 @@ export function buildHTMLStyles( ) } else if (transformTemplate) { style.transform = transformTemplate({}, "") + } else if (!latestValues.transform && style.transform) { + style.transform = "none" } if (hasTransformOrigin) { diff --git a/src/render/index.ts b/src/render/index.ts index 1c421eb978..6810681674 100644 --- a/src/render/index.ts +++ b/src/render/index.ts @@ -449,6 +449,10 @@ export const visualElement = * added to our map, old ones removed, and listeners updated. */ setProps(newProps) { + if (newProps.transformTemplate || props.transformTemplate) { + element.scheduleRender() + } + props = newProps lifecycles.updatePropListeners(newProps)