Skip to content

Commit

Permalink
Merge pull request #18 from Etesam913/fix-bug-with-context-provider-a…
Browse files Browse the repository at this point in the history
…s-child

🐛 Fixed bug in context provider in `<MagicMotion/>`
  • Loading branch information
Etesam913 authored Nov 23, 2023
2 parents 322dd0d + cff23e1 commit 5d37185
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 11 deletions.
12 changes: 11 additions & 1 deletion packages/react-magic-motion/tests/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { forwardRef, useRef, cloneElement } from "react";
import { forwardRef, useRef, cloneElement, createContext } from "react";
import type { ReactElement, ReactNode } from "react";

export function TestComponent({
Expand Down Expand Up @@ -48,3 +48,13 @@ export function cloneRootElem(rootElem: ReactElement): ReactNode {
exit: { opacity: 0 },
});
}

const ContextExample = createContext({});

export function ContextProviderParent(): JSX.Element {
return (
<ContextExample.Provider value={{}}>
<div>Testing</div>
</ContextExample.Provider>
);
}
31 changes: 30 additions & 1 deletion packages/react-magic-motion/tests/magic-motion.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@ import { render } from "@testing-library/react";
import { beforeAll, describe, expect, test, vi, afterEach } from "vitest";
import "@testing-library/jest-dom";
import { motion } from "framer-motion";
import { Profiler } from "react";
import { convertChildrenToMotionChildren } from "../utils/magic-animation";
import { MagicExit } from "../magic-exit";
import { MagicMotion } from "../magic-motion";
import { TestComponent, ParentComponent, ForwardedRefParent } from ".";
import {
TestComponent,
ParentComponent,
ForwardedRefParent,
ContextProviderParent,
} from ".";

describe("<MagicMotion> tests", () => {
const consoleMock = vi
Expand Down Expand Up @@ -370,4 +376,27 @@ describe("<MagicMotion> tests", () => {
</MagicMotion>
);
});

test("a context provider child", () => {
render(
<MagicMotion>
<ContextProviderParent />
</MagicMotion>
);
});

test("a react profiler child", () => {
render(
<MagicMotion>
<Profiler
id="ok"
onRender={() => {
return "ok";
}}
>
<div>test</div>
</Profiler>
</MagicMotion>
);
});
});
34 changes: 25 additions & 9 deletions packages/react-magic-motion/utils/magic-animation.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import type { FunctionComponent, Ref, ReactNode, ReactElement } from "react";
import { Children, createElement, isValidElement } from "react";
import { isMotionComponent, m } from "framer-motion";
import { isForwardRef, isPortal } from "react-is";
import {
isForwardRef,
isPortal,
isContextConsumer,
isContextProvider,
isProfiler,
} from "react-is";
import {
FORBIDDENELEMENTMESSAGE,
FUNCTIONCOMPONENTMESSAGE,
Expand All @@ -17,6 +23,20 @@ function isNodeText(node: ReactNode): boolean {
);
}

export function getIfComponentCanBeConverted(
node: React.ReactPortal | ReactElement<unknown>,
nodeType: string | React.ComponentType
): boolean {
return (
!isMotionComponent(nodeType) &&
!isPortal(node) &&
!isProfiler(node) &&
!isForwardRef(node) &&
!isContextProvider(node) &&
!isContextConsumer(node)
);
}

/** Sets the `layout` property depending on the type of the children*/
export function getLayoutValueFromChildren(
children: ReactNode
Expand Down Expand Up @@ -81,7 +101,7 @@ export function convertChildrenToMotionChildren(
}

// Checks if the child is a function component
let parent:ReactNode = null;
let parent: ReactNode = null;
while (typeof node.type === "function") {
if (isLoggingEnabled)
logSuccess(FUNCTIONCOMPONENTMESSAGE(node.type.name));
Expand All @@ -105,14 +125,10 @@ export function convertChildrenToMotionChildren(

// @ts-expect-error - This is a hack to get around the fact that the ref type is not correct
const nodeRef = isPortal(node) ? null : (node.ref as Ref<HTMLElement>);

// If the child is a motion component or forwardRef, we use that as the type otherwise convert it to a motion component
const shouldConvertNodeToMotionComponent = isMotionComponent(node.type) || isForwardRef(node)


// If the child is a motion component or forwardRef, we use that as the type otherwise convert it to a motion component
const typeOfNewElement = (
shouldConvertNodeToMotionComponent
? node.type
: m[childType]
getIfComponentCanBeConverted(node, node.type) ? m[childType] : node.type
) as string | FunctionComponent<any>;

const newElemChildren = convertChildrenToMotionChildren(
Expand Down

0 comments on commit 5d37185

Please sign in to comment.