Skip to content

Commit

Permalink
Adding motion.create() (#2787)
Browse files Browse the repository at this point in the history
* Adding motion.create and m.create

* Updating tests

* Deprecated motion()

* Fixing ssr test

* Removing old function calls
  • Loading branch information
mattgperry authored Sep 4, 2024
1 parent ed38c3c commit 5ae3495
Show file tree
Hide file tree
Showing 12 changed files with 47 additions and 44 deletions.
4 changes: 2 additions & 2 deletions dev/react/src/examples/Animation-variants.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Fragment, useState } from "react"
import { motion, createMotionComponent, useMotionValue } from "framer-motion"
import { motion, useMotionValue } from "framer-motion"

const MotionFragment = createMotionComponent(Fragment)
const MotionFragment = motion.create(Fragment)

export function App() {
const backgroundColor = useMotionValue("#f00")
Expand Down
4 changes: 2 additions & 2 deletions dev/react/src/examples/motion-custom-tag.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { createMotionComponent } from "framer-motion"
import { motion } from "framer-motion"

/**
* An example of creating a `motion` version of a custom element. This will render <global> into the HTML
*/

export const App = () => {
const CustomComponent = createMotionComponent("global")
const CustomComponent = motion.create("global")

return (
<CustomComponent
Expand Down
2 changes: 0 additions & 2 deletions packages/framer-motion/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
/**
* Components
*/
export { createMotionComponent } from "./render/components/motion/create"
export { createMinimalMotionComponent } from "./render/components/m/create"
export { motion } from "./render/components/motion/proxy"
export { m } from "./render/components/m/proxy"
export { AnimatePresence } from "./components/AnimatePresence"
Expand Down
10 changes: 5 additions & 5 deletions packages/framer-motion/src/motion/__tests__/component.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { render } from "../../../jest.setup"
import { fireEvent } from "@testing-library/react"
import { createMotionComponent, motion } from "framer-motion"
import { motion } from "framer-motion"
import * as React from "react"
import styled from "styled-components"

Expand All @@ -10,9 +10,9 @@ describe("motion component rendering and styles", () => {
expect(container.firstChild).toBeTruthy()
})

it("renders motion div component (using createMotionComponent) without type errors ", () => {
it("renders motion div component (using motion.create) without type errors ", () => {
// onTap is a motion component specific prop
const MotionDiv = createMotionComponent("div")
const MotionDiv = motion.create("div")
render(
<MotionDiv
id={"myCreatedMotionDiv"}
Expand Down Expand Up @@ -107,7 +107,7 @@ describe("motion component rendering and styles", () => {
<button type="submit" disabled ref={ref} />
)
)
const MotionComponent = createMotionComponent(Component)
const MotionComponent = motion.create(Component)

const promise = new Promise<Element>((resolve) => {
const { rerender } = render(
Expand Down Expand Up @@ -249,7 +249,7 @@ describe("motion component rendering and styles", () => {
background-color: #fff;
`

const MotionBox = createMotionComponent(Box)
const MotionBox = motion.create(Box)
const { container } = render(
<MotionBox style={{ backgroundColor: "#f00" }} />
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { render } from "../../../jest.setup"
import { createMotionComponent } from "../../render/components/motion/create"
import { motion as motionProxy } from "../../render/components/motion/proxy"
import { motionValue } from "../../value"

const motion = { div: createMotionComponent("div") }
const motion = { div: motionProxy.create("div") }

describe("Create DOM Motion component", () => {
test("Animates", async () => {
Expand Down
5 changes: 2 additions & 3 deletions packages/framer-motion/src/motion/__tests__/custom.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { render } from "../../../jest.setup"
import { motion, createMotionComponent, useMotionValue } from "../.."
import { motion, useMotionValue } from "../.."
import * as React from "react"
import { ForwardedRef } from "react"
import { MotionProps } from "../types"
Expand Down Expand Up @@ -96,5 +96,4 @@ function runTests(name: string, motionFactory: any) {
})
}

runTests("createMotionComponent()", createMotionComponent)
runTests("motion()", motion)
runTests("motion.create()", motion.create)
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import {
createMotionComponent,
isMotionComponent,
motion,
unwrapMotionComponent,
} from "../.."
import { isMotionComponent, motion, unwrapMotionComponent } from "../.."
import { forwardRef } from "react"

const CustomComp = forwardRef(() => <div />)

describe("isMotionComponent", () => {
it("returns true for motion components", () => {
expect(isMotionComponent(motion.div)).toBe(true)
expect(isMotionComponent(createMotionComponent(CustomComp))).toBe(true)
expect(isMotionComponent(motion.create(CustomComp))).toBe(true)
})

it("returns false for other components", () => {
Expand All @@ -23,7 +18,7 @@ describe("isMotionComponent", () => {
describe("unwrapMotionComponent", () => {
it("returns the wrapped component for motion components", () => {
expect(unwrapMotionComponent(motion.div)).toBe("div")
expect(unwrapMotionComponent(createMotionComponent(CustomComp))).toBe(
expect(unwrapMotionComponent(motion.create(CustomComp))).toBe(
CustomComp
)
})
Expand Down
18 changes: 9 additions & 9 deletions packages/framer-motion/src/motion/__tests__/ssr.test.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
import { Fragment, useRef, useState, forwardRef, ForwardedRef } from "react"
import { renderToString, renderToStaticMarkup } from "react-dom/server"
import { createMotionComponent, useMotionValue } from "../../"
import { useMotionValue } from "../../"
import { motion } from "../../render/components/motion"
import { motion as motionProxy } from "../../render/components/motion/proxy"
import { motionValue } from "../../value"
import { AnimatePresence } from "../../components/AnimatePresence"
import { Reorder } from "../../components/Reorder"

const MotionFragment = createMotionComponent(Fragment)
const MotionFragment = motion.create(Fragment)

function runTests(render: (components: any) => string) {
test("doesn't throw type or runtime errors", () => {
interface CustomProps {
foo: string
}

const CustomMotionComponent = createMotionComponent(
const CustomMotionComponent = motion.create(
forwardRef(
(props: CustomProps, ref: ForwardedRef<HTMLDivElement>) => {
return <div ref={ref} {...props} />
}
)
)
const CustomMotionDiv = createMotionComponent("div")
const CustomMotionCircle = createMotionComponent("circle")
const CustomMotionDiv = motion.create("div")
const CustomMotionCircle = motion.create("circle")

const ProxyCustomMotionComponent = motionProxy(
const ProxyCustomMotionComponent = motionProxy.create(
forwardRef(
(props: CustomProps, ref: ForwardedRef<HTMLInputElement>) => {
return <input ref={ref} {...props} />
}
)
)
const ProxyCustomMotionDiv = motionProxy("div")
const ProxyCustomMotionCircle = motionProxy("circle")
const ProxyCustomMotionDiv = motionProxy.create("div")
const ProxyCustomMotionCircle = motionProxy.create("circle")

function Component() {
const divRef = useRef<HTMLDivElement>(null)
Expand Down Expand Up @@ -152,7 +152,7 @@ function runTests(render: (components: any) => string) {

test("correctly renders custom HTML tag", () => {
const y = motionValue(200)
const CustomComponent = createMotionComponent("element-test")
const CustomComponent = motion.create("element-test")
const customElement = render(
<AnimatePresence>
<CustomComponent
Expand Down
10 changes: 2 additions & 8 deletions packages/framer-motion/src/motion/__tests__/variant.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,13 @@ import {
pointerUp,
render,
} from "../../../jest.setup"
import {
frame,
motion,
MotionConfig,
useMotionValue,
createMotionComponent,
} from "../../"
import { frame, motion, MotionConfig, useMotionValue } from "../../"
import { Fragment, useEffect, memo, useState } from "react"
import { Variants } from "../../types"
import { motionValue } from "../../value"
import { nextFrame } from "../../gestures/__tests__/utils"

const MotionFragment = createMotionComponent(Fragment)
const MotionFragment = motion.create(Fragment)

describe("animate prop as variant", () => {
test("animates to set variant", async () => {
Expand Down
19 changes: 16 additions & 3 deletions packages/framer-motion/src/render/components/create-proxy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { MotionProps } from "../../motion/types"
import { warning } from "../../utils/errors"
import { DOMMotionComponents } from "../dom/types"
import type { createMotionComponent } from "./motion/create"

Expand All @@ -15,8 +16,11 @@ export type CustomDomComponent<Props> = React.ForwardRefExoticComponent<
export function createDOMMotionComponentProxy(
componentFactory: typeof createMotionComponent
) {
type MotionProxy = typeof componentFactory &
DOMMotionComponents & { create: typeof componentFactory }

if (typeof Proxy === "undefined") {
return componentFactory as typeof componentFactory & DOMMotionComponents
return componentFactory as MotionProxy
}

/**
Expand All @@ -25,13 +29,22 @@ export function createDOMMotionComponentProxy(
*/
const componentCache = new Map<string, any>()

return new Proxy(componentFactory, {
const deprecatedFactoryFunction: typeof createMotionComponent = (
...args
) => {
warning(false, "motion() is deprecated. Use motion.create() instead.")
return componentFactory(...args)
}

return new Proxy(deprecatedFactoryFunction, {
/**
* Called when `motion` is referenced with a prop: `motion.div`, `motion.input` etc.
* The prop name is passed through as `key` and we can use that to generate a `motion`
* DOM component with that name.
*/
get: (_target, key: string) => {
if (key === "create") return componentFactory

/**
* If this element doesn't exist in the component cache, create it and cache.
*/
Expand All @@ -41,5 +54,5 @@ export function createDOMMotionComponentProxy(

return componentCache.get(key)!
},
}) as typeof componentFactory & DOMMotionComponents
}) as MotionProxy
}
2 changes: 2 additions & 0 deletions packages/framer-motion/src/render/components/m/namespace.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export { createMinimalMotionComponent as create } from "./create"

export {
MotionA as a,
MotionAbbr as abbr,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export { createMotionComponent as create } from "./create"

export {
MotionA as a,
MotionAbbr as abbr,
Expand Down

0 comments on commit 5ae3495

Please sign in to comment.