diff --git a/.github/README.md b/.github/README.md
index 9912977..4ccac7f 100644
--- a/.github/README.md
+++ b/.github/README.md
@@ -16,6 +16,24 @@ A component to integrate [P5.js](https://p5js.org/) sketches into
> in your sketches and much more besides, you can read more on the upcoming
> version of the [P5 docs](https://beta.p5js.org/).
+## ⚠️ Migration Notes
+
+The main component for rendering p5 sketches in React depends on your version:
+
+- Version 4 and earlier: use `ReactP5Wrapper`.
+- Version 5 and later: use `P5Canvas`.
+
+Both components work in the same way.
+
+Breaking changes in v5:
+
+1. Component rename
+ - `ReactP5Wrapper` → `P5Canvas`
+
+2. Types
+ - `P5WrapperProps` → `P5CanvasProps`
+ - `P5WrapperClassName` → `CanvasContainerClassName`
+
## Installation
To install, use the following command in the format appropriate to your chosen
@@ -27,8 +45,8 @@ package manager:
### Peer dependencies
-Please note that `p5`, `react` and `react-dom` are peer dependencies, meaning
-you should ensure they are installed before installing React P5 Wrapper.
+Please note that `p5`, `react` and `react-dom` are peer dependencies. Make sure
+they are installed in your project before installing this package.
```js
"peerDependencies": {
@@ -38,6 +56,20 @@ you should ensure they are installed before installing React P5 Wrapper.
},
```
+Version 5
+
+
+```js
+"peerDependencies": {
+ "p5": ">= 2.0.0",
+ "react": ">= 19.0.0",
+ "react-dom": ">= 19.0.0"
+},
+```
+
+
+
+
### TypeScript
If you would like to use Typescript, you should install `p5` types in the
@@ -114,14 +146,44 @@ export function App() {
}
```
+Version 5
+
+
+```jsx
+import * as React from "react";
+import { P5Canvas } from "@p5-wrapper/react";
+
+function sketch(p5) {
+ p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
+
+ p5.draw = () => {
+ p5.background(250);
+ p5.normalMaterial();
+ p5.push();
+ p5.rotateZ(p5.frameCount * 0.01);
+ p5.rotateX(p5.frameCount * 0.01);
+ p5.rotateY(p5.frameCount * 0.01);
+ p5.plane(100);
+ p5.pop();
+ };
+}
+
+export function App() {
+ return ;
+}
+```
+
+
+
+
### TypeScript
TypeScript sketches can be declared in two different ways, below you will find
two ways to declare a sketch, both examples do the exact same thing.
-In short though, the `ReactP5Wrapper` component requires you to pass a `sketch`
-prop. The `sketch` prop is simply a function which takes a `p5` instance as it's
-first and only argument.
+In short though, the component requires you to pass a `sketch` prop. The
+`sketch` prop is simply a function which takes a `p5` instance as it's first and
+only argument.
#### Option 1: Declaring a sketch using the `P5CanvasInstance` type
@@ -149,6 +211,36 @@ export function App() {
}
```
+Version 5
+
+
+```tsx
+import * as React from "react";
+import { P5Canvas, P5CanvasInstance } from "@p5-wrapper/react";
+
+function sketch(p5: P5CanvasInstance) {
+ p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
+
+ p5.draw = () => {
+ p5.background(250);
+ p5.normalMaterial();
+ p5.push();
+ p5.rotateZ(p5.frameCount * 0.01);
+ p5.rotateX(p5.frameCount * 0.01);
+ p5.rotateY(p5.frameCount * 0.01);
+ p5.plane(100);
+ p5.pop();
+ };
+}
+
+export function App() {
+ return ;
+}
+```
+
+
+
+
#### Option 2: Declaring a sketch using the `Sketch` type
Using the `Sketch` type has one nice benefit over using `P5CanvasInstance` and
@@ -185,6 +277,36 @@ export function App() {
}
```
+Version 5
+
+
+```tsx
+import * as React from "react";
+import { P5Canvas, Sketch } from "@p5-wrapper/react";
+
+const sketch: Sketch = p5 => {
+ p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
+
+ p5.draw = () => {
+ p5.background(250);
+ p5.normalMaterial();
+ p5.push();
+ p5.rotateZ(p5.frameCount * 0.01);
+ p5.rotateX(p5.frameCount * 0.01);
+ p5.rotateY(p5.frameCount * 0.01);
+ p5.plane(100);
+ p5.pop();
+ };
+};
+
+export function App() {
+ return ;
+}
+```
+
+
+
+
#### TypeScript Generics
We also support the use of Generics to add type definitions for your props. If
@@ -265,6 +387,60 @@ export function App() {
}
```
+Version 5
+
+
+```tsx
+import { P5Canvas, P5CanvasInstance, SketchProps } from "@p5-wrapper/react";
+import React, { useEffect, useState } from "react";
+
+type MySketchProps = SketchProps & {
+ rotation: number;
+};
+
+function sketch(p5: P5CanvasInstance) {
+ let rotation = 0;
+
+ p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
+
+ p5.updateWithProps = props => {
+ if (props.rotation) {
+ rotation = (props.rotation * Math.PI) / 180;
+ }
+ };
+
+ p5.draw = () => {
+ p5.background(100);
+ p5.normalMaterial();
+ p5.noStroke();
+ p5.push();
+ p5.rotateY(rotation);
+ p5.box(100);
+ p5.pop();
+ };
+}
+
+export function App() {
+ const [rotation, setRotation] = useState(0);
+
+ useEffect(() => {
+ const interval = setInterval(
+ () => setRotation(rotation => rotation + 100),
+ 100
+ );
+
+ return () => {
+ clearInterval(interval);
+ };
+ }, []);
+
+ return ;
+}
+```
+
+
+
+
##### Usage with the `Sketch` type
```tsx
@@ -315,6 +491,60 @@ export function App() {
}
```
+Version 5
+
+
+```tsx
+import { P5Canvas, Sketch, SketchProps } from "@p5-wrapper/react";
+import React, { useEffect, useState } from "react";
+
+type MySketchProps = SketchProps & {
+ rotation: number;
+};
+
+const sketch: Sketch = p5 => {
+ let rotation = 0;
+
+ p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
+
+ p5.updateWithProps = props => {
+ if (props.rotation) {
+ rotation = (props.rotation * Math.PI) / 180;
+ }
+ };
+
+ p5.draw = () => {
+ p5.background(100);
+ p5.normalMaterial();
+ p5.noStroke();
+ p5.push();
+ p5.rotateY(rotation);
+ p5.box(100);
+ p5.pop();
+ };
+};
+
+export function App() {
+ const [rotation, setRotation] = useState(0);
+
+ useEffect(() => {
+ const interval = setInterval(
+ () => setRotation(rotation => rotation + 100),
+ 100
+ );
+
+ return () => {
+ clearInterval(interval);
+ };
+ }, []);
+
+ return ;
+}
+```
+
+
+
+
### Using abstracted setup and draw functions
```jsx
@@ -350,23 +580,61 @@ export function App() {
}
```
+Version 5
+
+
+```jsx
+import * as React from "react";
+import { P5Canvas } from "@p5-wrapper/react";
+
+function setup(p5) {
+ return () => {
+ p5.createCanvas(600, 400, p5.WEBGL);
+ };
+}
+
+function draw(p5) {
+ return () => {
+ p5.background(250);
+ p5.normalMaterial();
+ p5.push();
+ p5.rotateZ(p5.frameCount * 0.01);
+ p5.rotateX(p5.frameCount * 0.01);
+ p5.rotateY(p5.frameCount * 0.01);
+ p5.plane(100);
+ p5.pop();
+ };
+}
+
+function sketch(p5) {
+ p5.setup = setup(p5);
+ p5.draw = draw(p5);
+}
+
+export function App() {
+ return ;
+}
+```
+
+
+
+
### Props
-The only required property of the `ReactP5Wrapper` component is the `sketch`
-prop. The `sketch` prop is a function that will be passed a p5 instance to use
-for rendering your sketches as shown in [the usage section](#usage) above.
+The only required property is the sketch prop. The sketch prop is a function
+that will be passed a p5 instance to use for rendering your sketches (see the
+usage section above).
-You can pass as many custom props as you want to the `ReactP5Wrapper` component
-and these will all be passed into the `updateWithProps` method if you have
-defined it within your sketch.
+You can pass as many custom props as you want. These will be passed into the
+updateWithProps method if you have defined it within your sketch.
#### Reacting to props
In the below example you see the `updateWithProps` method being used. This is
called when the component initially renders and when the props passed to the
wrapper are changed, if it is set within your sketch. This way we can render our
-`ReactP5Wrapper` component and react to component prop changes directly within
-our sketches!
+component (`ReactP5Wrapper` in v4, or `P5Canvas` in v5) and react to component
+prop changes directly within our sketches!
```jsx
import { ReactP5Wrapper } from "@p5-wrapper/react";
@@ -412,12 +680,63 @@ export function App() {
}
```
+Version 5
+
+
+```jsx
+import { P5Canvas } from "@p5-wrapper/react";
+import React, { useEffect, useState } from "react";
+
+function sketch(p5) {
+ let rotation = 0;
+
+ p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
+
+ p5.updateWithProps = props => {
+ if (props.rotation) {
+ rotation = (props.rotation * Math.PI) / 180;
+ }
+ };
+
+ p5.draw = () => {
+ p5.background(100);
+ p5.normalMaterial();
+ p5.noStroke();
+ p5.push();
+ p5.rotateY(rotation);
+ p5.box(100);
+ p5.pop();
+ };
+}
+
+export function App() {
+ const [rotation, setRotation] = useState(0);
+
+ useEffect(() => {
+ const interval = setInterval(
+ () => setRotation(rotation => rotation + 100),
+ 100
+ );
+
+ return () => {
+ clearInterval(interval);
+ };
+ }, []);
+
+ return ;
+}
+```
+
+
+
+
### Children
To render a component on top of the sketch, you can add it as a child of the
-`ReactP5Wrapper` component and then use the exported `P5WrapperClassName`
-constant in your css-in-js library of choice to style one element above the
-other via css.
+component (`ReactP5Wrapper` in v4, or `P5Canvas` in v5) and then use the
+exported constant (`P5WrapperClassName` in v4, or `CanvasContainerClassName` in
+v5) in your css-in-js library of choice to style one element above the other via
+css.
For instance, using [styled components](https://styled-components.com), we could
center some text on top of our sketch like so:
@@ -470,6 +789,61 @@ export function App() {
}
```
+Version 5
+
+
+```jsx
+import { CanvasContainerClassName, P5Canvas } from "@p5-wrapper/react";
+import styled, { createGlobalStyle } from "styled-components";
+
+const GlobalWrapperStyles = createGlobalStyle`
+ .${CanvasContainerClassName} {
+ position: relative;
+ }
+`;
+
+const StyledCentredText = styled.span`
+ .${CanvasContainerClassName} & {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ color: white;
+ font-size: 2rem;
+ margin: 0;
+ text-align: center;
+ }
+`;
+
+export function App() {
+ const [rotation, setRotation] = useState(0);
+
+ useEffect(() => {
+ const interval = setInterval(
+ () => setRotation(rotation => rotation + 100),
+ 100
+ );
+
+ return () => {
+ clearInterval(interval);
+ };
+ }, []);
+
+ return (
+
+
+
+ Hello world!
+
+
+ );
+}
+```
+
+
+
+
+
Of course, you can also use any other css-in-js library or by just using simple
css to achieve almost anything you can imagine just by using the wrapper class
as your root selector.
@@ -543,6 +917,72 @@ export function App() {
}
```
+Version 5
+
+
+```jsx
+import * as React from "react";
+import { P5Canvas } from "@p5-wrapper/react";
+
+function sketchOne(p5) {
+ p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
+
+ p5.draw = () => {
+ p5.background(250);
+ p5.normalMaterial();
+ p5.push();
+ p5.rotateZ(p5.frameCount * 0.01);
+ p5.rotateX(p5.frameCount * 0.01);
+ p5.rotateY(p5.frameCount * 0.01);
+ p5.plane(100);
+ p5.pop();
+ };
+}
+
+function sketchTwo(p5) {
+ p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
+
+ p5.draw = () => {
+ p5.background(500);
+ p5.normalMaterial();
+ p5.push();
+ p5.rotateZ(p5.frameCount * 0.01);
+ p5.rotateX(p5.frameCount * 0.01);
+ p5.rotateY(p5.frameCount * 0.01);
+ p5.plane(100);
+ p5.pop();
+ };
+}
+
+export function App() {
+ const [sketch, setSketch] = React.useState(undefined);
+ const chooseNothing = () => setSketch(undefined);
+ const chooseSketchOne = () => setSketch(sketchOne);
+ const chooseSketchTwo = () => setSketch(sketchTwo);
+
+ return (
+ <>
+
+
+ Choose nothing
+
+
+ Choose sketch 1
+
+
+ Choose sketch 2
+
+
+ No sketch selected yet.} sketch={sketch} />
+ >
+ );
+}
+```
+
+
+
+
+
In this case, by default the fallback UI containing
`No sketch selected yet. ` will be rendered, then if you select a
sketch, it will be rendered until you choose to once again "show nothing" which
@@ -608,6 +1048,55 @@ export function App() {
}
```
+Version 5
+
+
+```tsx
+import * as React from "react";
+import { P5Canvas, P5CanvasInstance } from "@p5-wrapper/react";
+
+// This child will throw an error, oh no!
+function ErrorChild() {
+ throw new Error("oops");
+}
+
+// This view will catch the thrown error and give you access to what exactly was thrown.
+function ErrorUI(error: any) {
+ if (error instanceof Error) {
+ return
An error occured: {error.message}
;
+ }
+
+ return An unknown error occured: {error.toString()}
;
+}
+
+function sketch(p5: P5CanvasInstance) {
+ p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
+
+ p5.draw = () => {
+ p5.background(250);
+ p5.normalMaterial();
+ p5.push();
+ p5.rotateZ(p5.frameCount * 0.01);
+ p5.rotateX(p5.frameCount * 0.01);
+ p5.rotateY(p5.frameCount * 0.01);
+ p5.plane(100);
+ p5.pop();
+ };
+}
+
+export function App() {
+ return (
+
+
+
+ );
+}
+```
+
+
+
+
+
Instead of the sketch, this will render `An error occured: oops
`. Note
that in truth, the `ErrorView` will **always** receive `any` values since JS /
TS allow you to `throw` whatever values you want to, this is why we have to add
@@ -651,6 +1140,41 @@ export function App() {
}
```
+Version 5
+
+
+```tsx
+import * as React from "react";
+import { P5Canvas, P5CanvasInstance } from "@p5-wrapper/react";
+
+function LoadingUI() {
+ return
The sketch is being loaded.
;
+}
+
+function sketch(p5: P5CanvasInstance) {
+ p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
+
+ p5.draw = () => {
+ p5.background(250);
+ p5.normalMaterial();
+ p5.push();
+ p5.rotateZ(p5.frameCount * 0.01);
+ p5.rotateX(p5.frameCount * 0.01);
+ p5.rotateY(p5.frameCount * 0.01);
+ p5.plane(100);
+ p5.pop();
+ };
+}
+
+export function App() {
+ return ;
+}
+```
+
+
+
+
+
In the initial period between the sketch render starting and it's lazy loading
ending, the `LoadingUI` will be shown!
@@ -739,6 +1263,74 @@ export default function App() {
}
```
+Version 5
+
+
+```tsx
+import * as p5 from "p5";
+import { P5Canvas, Sketch } from "@p5-wrapper/react";
+import React, { useEffect, useState } from "react";
+
+(window as any).p5 = p5;
+
+await import("p5/lib/addons/p5.sound");
+
+const sketch: Sketch = p5 => {
+ let song: p5.SoundFile;
+ let button: p5.Element;
+
+ p5.setup = () => {
+ p5.createCanvas(600, 400, p5.WEBGL);
+ p5.background(255, 0, 0);
+ button = p5.createButton("Toggle audio");
+
+ button.mousePressed(() => {
+ if (!song) {
+ const songPath = "/piano.mp3";
+ song = p5.loadSound(
+ songPath,
+ () => {
+ song.play();
+ },
+ () => {
+ console.error(
+ `Could not load the requested sound file ${songPath}`
+ );
+ }
+ );
+ return;
+ }
+
+ if (!song.isPlaying()) {
+ song.play();
+ return;
+ }
+
+ song.pause();
+ });
+ };
+
+ p5.draw = () => {
+ p5.background(250);
+ p5.normalMaterial();
+ p5.push();
+ p5.rotateZ(p5.frameCount * 0.01);
+ p5.rotateX(p5.frameCount * 0.01);
+ p5.rotateY(p5.frameCount * 0.01);
+ p5.plane(100);
+ p5.pop();
+ };
+};
+
+export default function App() {
+ return ;
+}
+```
+
+
+
+
+
In this Typescript + React example, we can see a few key things.
- Firstly we need to set `p5` on the `window` object manually. This is because
diff --git a/config/vite/library.ts b/config/vite/library.ts
index 144b53a..09f1c8d 100644
--- a/config/vite/library.ts
+++ b/config/vite/library.ts
@@ -26,8 +26,8 @@ export function library(root: string): UserConfig {
emptyOutDir: true,
lib: {
entry: resolve(root, "src", "main.tsx"),
- name: "ReactP5Wrapper",
- fileName: "ReactP5Wrapper",
+ name: "P5Canvas",
+ fileName: "P5Canvas",
formats: ["es", "cjs"]
},
rollupOptions: {
diff --git a/demo/app.jsx b/demo/app.jsx
index 4124ef9..34db3b0 100644
--- a/demo/app.jsx
+++ b/demo/app.jsx
@@ -1,4 +1,4 @@
-import { ReactP5Wrapper } from "@/main.tsx";
+import { P5Canvas } from "@/main.tsx";
import React, { useCallback, useMemo, useState } from "react";
import { createRoot } from "react-dom/client";
@@ -61,7 +61,7 @@ function App() {
return (
<>
-
+
{state.sketch === record && (
Start Recording
diff --git a/src/components/P5Canvas.tsx b/src/components/P5Canvas.tsx
new file mode 100644
index 0000000..7251a7e
--- /dev/null
+++ b/src/components/P5Canvas.tsx
@@ -0,0 +1,6 @@
+import * as React from "react";
+import { propsAreEqual } from "@utils/propsAreEqual";
+
+const P5CanvasGuard = React.lazy(() => import("@components/P5CanvasGuard"));
+
+export const P5Canvas = React.memo(P5CanvasGuard, propsAreEqual);
diff --git a/src/components/ReactP5WrapperGuard.tsx b/src/components/P5CanvasGuard.tsx
similarity index 66%
rename from src/components/ReactP5WrapperGuard.tsx
rename to src/components/P5CanvasGuard.tsx
index 0b11d71..a6f5056 100644
--- a/src/components/ReactP5WrapperGuard.tsx
+++ b/src/components/P5CanvasGuard.tsx
@@ -1,13 +1,13 @@
import * as React from "react";
-import { type P5WrapperProps } from "@contracts/P5WrapperProps";
-import { type P5WrapperPropsWithSketch } from "@contracts/P5WrapperPropsWithSketch";
+import { type P5CanvasProps } from "@contracts/P5CanvasProps";
+import { type P5CanvasPropsWithSketch } from "@contracts/P5CanvasPropsWithSketch";
import { type SketchProps } from "@contracts/SketchProps";
import { logErrorBoundaryError } from "@utils/logErrorBoundaryError";
import { ReactNode } from "react";
import { FallbackProps } from "react-error-boundary";
-const ReactP5WrapperWithSketch = React.lazy(
- () => import("@components/ReactP5WrapperWithSketch")
+const P5CanvasWithSketch = React.lazy(
+ () => import("@components/P5CanvasWithSketch")
);
const ErrorBoundary = React.lazy(() =>
@@ -16,11 +16,11 @@ const ErrorBoundary = React.lazy(() =>
}))
);
-const ReactP5WrapperGuard =
(
- props: P5WrapperProps
+const P5CanvasGuard = (
+ props: P5CanvasProps
) => {
if (props.sketch === undefined) {
- console.error("[ReactP5Wrapper] The `sketch` prop is required.");
+ console.error("[P5Canvas] The `sketch` prop is required.");
return props.fallback?.() ?? null;
}
@@ -43,13 +43,13 @@ const ReactP5WrapperGuard = (
props.loading?.() ?? 🚀 Loading...
}
>
- )}
+ {...(props as unknown as P5CanvasPropsWithSketch)}
/>
);
};
-export default ReactP5WrapperGuard;
+export default P5CanvasGuard;
diff --git a/src/components/P5CanvasWithSketch.tsx b/src/components/P5CanvasWithSketch.tsx
new file mode 100644
index 0000000..7916f19
--- /dev/null
+++ b/src/components/P5CanvasWithSketch.tsx
@@ -0,0 +1,56 @@
+import * as React from "react";
+import { CanvasContainerClassName } from "@constants/CanvasContainerClassName";
+import { type CanvasContainerRef } from "@contracts/CanvasContainerRef";
+import { type P5CanvasInstanceRef } from "@contracts/P5CanvasInstanceRef";
+import { type P5CanvasPropsWithSketch } from "@contracts/P5CanvasPropsWithSketch";
+import { type SketchProps } from "@contracts/SketchProps";
+import { removeP5CanvasInstance } from "@utils/removeP5CanvasInstance";
+import { updateP5CanvasInstance } from "@utils/updateP5CanvasInstance";
+import { withoutKeys } from "@utils/withoutKeys";
+
+const P5CanvasWithSketch = (
+ props: P5CanvasPropsWithSketch
+) => {
+ const canvasContainerRef: CanvasContainerRef = React.useRef(null);
+ const p5CanvasInstanceRef: P5CanvasInstanceRef = React.useRef(null);
+ const sketchProps: SketchProps = React.useMemo(
+ () =>
+ withoutKeys(props, [
+ "sketch",
+ "fallback",
+ "loading",
+ "error",
+ "children"
+ ]),
+ [props]
+ );
+
+ React.useEffect(() => {
+ p5CanvasInstanceRef.current = updateP5CanvasInstance(
+ p5CanvasInstanceRef,
+ canvasContainerRef,
+ props.sketch
+ );
+ }, [props.sketch]);
+
+ React.useEffect(() => {
+ /** @see https://github.com/P5-wrapper/react/discussions/360 */
+ p5CanvasInstanceRef.current?.updateWithProps?.(
+ sketchProps as unknown as Props
+ );
+ }, [sketchProps, canvasContainerRef, p5CanvasInstanceRef]);
+
+ React.useEffect(() => () => removeP5CanvasInstance(p5CanvasInstanceRef), []);
+
+ return (
+
+ {props.children}
+
+ );
+};
+
+export default P5CanvasWithSketch;
diff --git a/src/components/ReactP5Wrapper.tsx b/src/components/ReactP5Wrapper.tsx
deleted file mode 100644
index 508c5b5..0000000
--- a/src/components/ReactP5Wrapper.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import * as React from "react";
-import { propsAreEqual } from "@utils/propsAreEqual";
-
-const ReactP5WrapperGuard = React.lazy(
- () => import("@components/ReactP5WrapperGuard")
-);
-
-export const ReactP5Wrapper = React.memo(ReactP5WrapperGuard, propsAreEqual);
diff --git a/src/components/ReactP5WrapperWithSketch.tsx b/src/components/ReactP5WrapperWithSketch.tsx
deleted file mode 100644
index 1f7d5be..0000000
--- a/src/components/ReactP5WrapperWithSketch.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import * as React from "react";
-import { P5WrapperClassName } from "@constants/P5WrapperClassName";
-import { type CanvasInstanceRef } from "@contracts/CanvasInstanceRef";
-import { type P5WrapperPropsWithSketch } from "@contracts/P5WrapperPropsWithSketch";
-import { type SketchProps } from "@contracts/SketchProps";
-import { type WrapperRef } from "@contracts/WrapperRef";
-import { removeCanvasInstance } from "@utils/removeCanvasInstance";
-import { updateCanvasInstance } from "@utils/updateCanvasInstance";
-import { withoutKeys } from "@utils/withoutKeys";
-
-const ReactP5WrapperWithSketch = (
- props: P5WrapperPropsWithSketch
-) => {
- const wrapperRef: WrapperRef = React.useRef(null);
- const canvasInstanceRef: CanvasInstanceRef = React.useRef(null);
- const userProvidedProps: SketchProps = React.useMemo(
- () =>
- withoutKeys(props, [
- "sketch",
- "fallback",
- "loading",
- "error",
- "children"
- ]),
- [props]
- );
-
- React.useEffect(() => {
- canvasInstanceRef.current = updateCanvasInstance(
- canvasInstanceRef,
- wrapperRef,
- props.sketch
- );
- }, [props.sketch]);
-
- React.useEffect(() => {
- /** @see https://github.com/P5-wrapper/react/discussions/360 */
- canvasInstanceRef.current?.updateWithProps?.(
- userProvidedProps as unknown as Props
- );
- }, [userProvidedProps, wrapperRef, canvasInstanceRef]);
-
- React.useEffect(() => () => removeCanvasInstance(canvasInstanceRef), []);
-
- return (
-
- {props.children}
-
- );
-};
-
-export default ReactP5WrapperWithSketch;
diff --git a/src/constants/CanvasContainerClassName.ts b/src/constants/CanvasContainerClassName.ts
new file mode 100644
index 0000000..ce9a05e
--- /dev/null
+++ b/src/constants/CanvasContainerClassName.ts
@@ -0,0 +1 @@
+export const CanvasContainerClassName = "canvas-container";
diff --git a/src/constants/P5WrapperClassName.ts b/src/constants/P5WrapperClassName.ts
deleted file mode 100644
index a00bbc4..0000000
--- a/src/constants/P5WrapperClassName.ts
+++ /dev/null
@@ -1 +0,0 @@
-export const P5WrapperClassName = "p5-wrapper-react";
diff --git a/src/contracts/CanvasContainer.ts b/src/contracts/CanvasContainer.ts
new file mode 100644
index 0000000..6492afa
--- /dev/null
+++ b/src/contracts/CanvasContainer.ts
@@ -0,0 +1 @@
+export type CanvasContainer = HTMLDivElement;
diff --git a/src/contracts/CanvasContainerRef.ts b/src/contracts/CanvasContainerRef.ts
new file mode 100644
index 0000000..546b5fa
--- /dev/null
+++ b/src/contracts/CanvasContainerRef.ts
@@ -0,0 +1,4 @@
+import { type CanvasContainer } from "@contracts/CanvasContainer";
+import { type RefObject } from "react";
+
+export type CanvasContainerRef = RefObject;
diff --git a/src/contracts/CanvasInstanceRef.ts b/src/contracts/P5CanvasInstanceRef.ts
similarity index 62%
rename from src/contracts/CanvasInstanceRef.ts
rename to src/contracts/P5CanvasInstanceRef.ts
index 12c09d5..ab8bfac 100644
--- a/src/contracts/CanvasInstanceRef.ts
+++ b/src/contracts/P5CanvasInstanceRef.ts
@@ -2,5 +2,6 @@ import { type P5CanvasInstance } from "@contracts/P5CanvasInstance";
import { type SketchProps } from "@contracts/SketchProps";
import { type RefObject } from "react";
-export type CanvasInstanceRef =
+/** Ref to the active p5.js sketch instance controlling the canvas */
+export type P5CanvasInstanceRef =
RefObject | null>;
diff --git a/src/contracts/P5WrapperProps.ts b/src/contracts/P5CanvasProps.ts
similarity index 75%
rename from src/contracts/P5WrapperProps.ts
rename to src/contracts/P5CanvasProps.ts
index ecb7a6e..3a0722d 100644
--- a/src/contracts/P5WrapperProps.ts
+++ b/src/contracts/P5CanvasProps.ts
@@ -2,5 +2,5 @@ import { type InputProps } from "@contracts/InputProps";
import { type SketchProps } from "@contracts/SketchProps";
import { type WithChildren } from "@contracts/WithChildren";
-export type P5WrapperProps =
+export type P5CanvasProps =
WithChildren>;
diff --git a/src/contracts/P5CanvasPropsWithSketch.ts b/src/contracts/P5CanvasPropsWithSketch.ts
new file mode 100644
index 0000000..8a75061
--- /dev/null
+++ b/src/contracts/P5CanvasPropsWithSketch.ts
@@ -0,0 +1,6 @@
+import { type P5CanvasProps } from "@contracts/P5CanvasProps";
+import { type Sketch } from "@contracts/Sketch";
+import { type SketchProps } from "@contracts/SketchProps";
+
+export type P5CanvasPropsWithSketch =
+ P5CanvasProps & { sketch: Sketch };
diff --git a/src/contracts/P5WrapperPropsWithSketch.ts b/src/contracts/P5WrapperPropsWithSketch.ts
deleted file mode 100644
index 2836d71..0000000
--- a/src/contracts/P5WrapperPropsWithSketch.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { type P5WrapperProps } from "@contracts/P5WrapperProps";
-import { type Sketch } from "@contracts/Sketch";
-import { type SketchProps } from "@contracts/SketchProps";
-
-export type P5WrapperPropsWithSketch =
- P5WrapperProps & { sketch: Sketch };
diff --git a/src/contracts/Wrapper.ts b/src/contracts/Wrapper.ts
deleted file mode 100644
index 8fc34d1..0000000
--- a/src/contracts/Wrapper.ts
+++ /dev/null
@@ -1 +0,0 @@
-export type Wrapper = HTMLDivElement;
diff --git a/src/contracts/WrapperRef.ts b/src/contracts/WrapperRef.ts
deleted file mode 100644
index 6961c2a..0000000
--- a/src/contracts/WrapperRef.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import { type Wrapper } from "@contracts/Wrapper";
-import { type RefObject } from "react";
-
-export type WrapperRef = RefObject;
diff --git a/src/main.tsx b/src/main.tsx
index 5531cc7..eb272f0 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -1,6 +1,6 @@
-export { ReactP5Wrapper } from "@components/ReactP5Wrapper";
-export { P5WrapperClassName } from "@constants/P5WrapperClassName";
+export { P5Canvas } from "@components/P5Canvas";
+export { CanvasContainerClassName } from "@constants/CanvasContainerClassName";
export { type P5CanvasInstance } from "@contracts/P5CanvasInstance";
-export { type P5WrapperProps } from "@contracts/P5WrapperProps";
+export { type P5CanvasProps } from "@contracts/P5CanvasProps";
export { type Sketch } from "@contracts/Sketch";
export { type SketchProps } from "@contracts/SketchProps";
diff --git a/src/utils/createCanvasInstance.ts b/src/utils/createP5CanvasInstance.ts
similarity index 55%
rename from src/utils/createCanvasInstance.ts
rename to src/utils/createP5CanvasInstance.ts
index d764d7b..4f4337f 100644
--- a/src/utils/createCanvasInstance.ts
+++ b/src/utils/createP5CanvasInstance.ts
@@ -1,12 +1,12 @@
+import { type CanvasContainer } from "@contracts/CanvasContainer";
import p5 from "@contracts/p5";
import { type P5CanvasInstance } from "@contracts/P5CanvasInstance";
import { type Sketch } from "@contracts/Sketch";
import { type SketchProps } from "@contracts/SketchProps";
-import { type Wrapper } from "@contracts/Wrapper";
-export function createCanvasInstance(
+export function createP5CanvasInstance(
sketch: Sketch,
- wrapper: Wrapper
+ canvasContainer: CanvasContainer
): P5CanvasInstance {
- return new p5(sketch, wrapper);
+ return new p5(sketch, canvasContainer);
}
diff --git a/src/utils/logErrorBoundaryError.ts b/src/utils/logErrorBoundaryError.ts
index 300b10a..8761309 100644
--- a/src/utils/logErrorBoundaryError.ts
+++ b/src/utils/logErrorBoundaryError.ts
@@ -1,5 +1,5 @@
const errorIntroduction =
- "[ReactP5Wrapper] The error boundary was triggered. The error message was:";
+ "[P5Canvas] The error boundary was triggered. The error message was:";
function tidyErrorLogText(text: string): string {
return text
diff --git a/src/utils/propsAreEqual.ts b/src/utils/propsAreEqual.ts
index cfd84ae..f436dcc 100644
--- a/src/utils/propsAreEqual.ts
+++ b/src/utils/propsAreEqual.ts
@@ -1,10 +1,10 @@
-import { type P5WrapperProps } from "@contracts/P5WrapperProps";
+import { type P5CanvasProps } from "@contracts/P5CanvasProps";
import { type SketchProps } from "@contracts/SketchProps";
import diff from "microdiff";
export function propsAreEqual(
- previous: P5WrapperProps,
- next: P5WrapperProps
+ previous: P5CanvasProps,
+ next: P5CanvasProps
) {
const differences = diff(previous, next);
diff --git a/src/utils/removeCanvasInstance.ts b/src/utils/removeCanvasInstance.ts
deleted file mode 100644
index 2dba2b5..0000000
--- a/src/utils/removeCanvasInstance.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { type CanvasInstanceRef } from "@contracts/CanvasInstanceRef";
-import { type SketchProps } from "@contracts/SketchProps";
-
-export function removeCanvasInstance(
- canvasInstanceRef: CanvasInstanceRef
-) {
- canvasInstanceRef.current?.remove();
- canvasInstanceRef.current = null;
-}
diff --git a/src/utils/removeP5CanvasInstance.ts b/src/utils/removeP5CanvasInstance.ts
new file mode 100644
index 0000000..19d0cc1
--- /dev/null
+++ b/src/utils/removeP5CanvasInstance.ts
@@ -0,0 +1,9 @@
+import { type P5CanvasInstanceRef } from "@contracts/P5CanvasInstanceRef";
+import { type SketchProps } from "@contracts/SketchProps";
+
+export function removeP5CanvasInstance(
+ p5CanvasInstanceRef: P5CanvasInstanceRef
+) {
+ p5CanvasInstanceRef.current?.remove();
+ p5CanvasInstanceRef.current = null;
+}
diff --git a/src/utils/updateCanvasInstance.ts b/src/utils/updateCanvasInstance.ts
deleted file mode 100644
index e8d9259..0000000
--- a/src/utils/updateCanvasInstance.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { type CanvasInstanceRef } from "@contracts/CanvasInstanceRef";
-import { type Sketch } from "@contracts/Sketch";
-import { type SketchProps } from "@contracts/SketchProps";
-import { type WrapperRef } from "@contracts/WrapperRef";
-import { createCanvasInstance } from "@utils/createCanvasInstance";
-import { removeCanvasInstance } from "@utils/removeCanvasInstance";
-
-export function updateCanvasInstance(
- canvasInstanceRef: CanvasInstanceRef,
- wrapperRef: WrapperRef,
- sketch: Sketch
-) {
- if (wrapperRef.current === null) {
- return null;
- }
-
- removeCanvasInstance(canvasInstanceRef);
-
- return createCanvasInstance(sketch, wrapperRef.current);
-}
diff --git a/src/utils/updateP5CanvasInstance.ts b/src/utils/updateP5CanvasInstance.ts
new file mode 100644
index 0000000..9a63a01
--- /dev/null
+++ b/src/utils/updateP5CanvasInstance.ts
@@ -0,0 +1,20 @@
+import { type CanvasContainerRef } from "@contracts/CanvasContainerRef";
+import { type P5CanvasInstanceRef } from "@contracts/P5CanvasInstanceRef";
+import { type Sketch } from "@contracts/Sketch";
+import { type SketchProps } from "@contracts/SketchProps";
+import { createP5CanvasInstance } from "@utils/createP5CanvasInstance";
+import { removeP5CanvasInstance } from "@utils/removeP5CanvasInstance";
+
+export function updateP5CanvasInstance(
+ p5CanvasInstanceRef: P5CanvasInstanceRef,
+ canvasContainerRef: CanvasContainerRef,
+ sketch: Sketch
+) {
+ if (canvasContainerRef.current === null) {
+ return null;
+ }
+
+ removeP5CanvasInstance(p5CanvasInstanceRef);
+
+ return createP5CanvasInstance(sketch, canvasContainerRef.current);
+}
diff --git a/tests/components/ReactP5Wrapper.test.tsx b/tests/components/P5Canvas.test.tsx
similarity index 75%
rename from tests/components/ReactP5Wrapper.test.tsx
rename to tests/components/P5Canvas.test.tsx
index 0cdeaca..7d6f70f 100644
--- a/tests/components/ReactP5Wrapper.test.tsx
+++ b/tests/components/P5Canvas.test.tsx
@@ -1,5 +1,5 @@
-import { ReactP5Wrapper } from "@components/ReactP5Wrapper";
-import { P5WrapperClassName } from "@constants/P5WrapperClassName";
+import { P5Canvas } from "@components/P5Canvas";
+import { CanvasContainerClassName } from "@constants/CanvasContainerClassName";
import { type P5CanvasInstance } from "@contracts/P5CanvasInstance";
import { type Sketch } from "@contracts/Sketch";
import { render, RenderResult, waitFor } from "@testing-library/react";
@@ -17,8 +17,8 @@ function createSketch(
async function waitForCanvas(findByTestId: RenderResult["findByTestId"]) {
return await waitFor(async () => {
- const wrapper = await findByTestId("wrapper");
- const canvas = wrapper.querySelector("canvas");
+ const canvasContainer = await findByTestId("canvas-container");
+ const canvas = canvasContainer.querySelector("canvas");
assert(canvas instanceof HTMLCanvasElement);
@@ -36,12 +36,12 @@ async function waitForLoading(findByTestId: RenderResult["findByTestId"]) {
});
}
-describe("ReactP5Wrapper", () => {
+describe("P5Canvas", () => {
describe("Rendering", () => {
describe("Client", () => {
- it("Renders the canvas into the wrapping element", async () => {
+ it("Renders the P5 canvas into the container element", async () => {
const sketch = createSketch();
- const { findByTestId } = render( );
+ const { findByTestId } = render( );
const canvas = await waitForCanvas(findByTestId);
expect(canvas).toBeInstanceOf(HTMLCanvasElement);
@@ -49,30 +49,28 @@ describe("ReactP5Wrapper", () => {
it("Recreates the P5 instance when the sketch is changed", async () => {
const sketch = createSketch();
- const { rerender, findByTestId } = render(
-
- );
+ const { rerender, findByTestId } = render( );
- rerender( );
+ rerender( );
const canvas = await waitForCanvas(findByTestId);
expect(canvas).toBeInstanceOf(HTMLCanvasElement);
});
- it("Adds a utility css class to the wrapping element", async () => {
+ it("Adds a utility css class to the container element", async () => {
const sketch = createSketch();
- const { findByTestId } = render( );
+ const { findByTestId } = render( );
- const wrapper = await findByTestId("wrapper");
+ const canvasContainer = await findByTestId("canvas-container");
- expect(wrapper).toBeInstanceOf(HTMLDivElement);
- expect(wrapper.className).toBe(P5WrapperClassName);
+ expect(canvasContainer).toBeInstanceOf(HTMLDivElement);
+ expect(canvasContainer.className).toBe(CanvasContainerClassName);
});
it("Unmounts the canvas when the element is removed from the DOM", async () => {
const sketch = createSketch();
const { container, unmount, findByTestId } = render(
-
+
);
await waitForCanvas(findByTestId);
@@ -85,7 +83,7 @@ describe("ReactP5Wrapper", () => {
});
it("Should not render anything when the `sketch` and `fallback` props are not provided", () => {
- const { container } = render( );
+ const { container } = render( );
expect(container.innerHTML).toBe("");
});
@@ -96,12 +94,12 @@ describe("ReactP5Wrapper", () => {
.spyOn(console, "error")
.mockImplementation(errorLogger);
- render( );
+ render( );
await waitFor(() => {
expect(errorLoggerSpy).toHaveBeenCalledOnce();
expect(errorLoggerSpy).toHaveBeenCalledWith(
- "[ReactP5Wrapper] The `sketch` prop is required."
+ "[P5Canvas] The `sketch` prop is required."
);
errorLoggerSpy.mockReset();
@@ -111,9 +109,7 @@ describe("ReactP5Wrapper", () => {
it("Should use the fallback UI if the sketch is undefined on initial render", async () => {
const fallbackView = vi.fn(() =>
);
- const { findByTestId } = render(
-
- );
+ const { findByTestId } = render( );
const fallback = await findByTestId("fallback");
@@ -125,12 +121,12 @@ describe("ReactP5Wrapper", () => {
const sketch = createSketch();
const fallbackView = vi.fn(() =>
);
const { rerender, findByTestId } = render(
- Oh no } sketch={sketch} />
+ Oh no } sketch={sketch} />
);
await waitForCanvas(findByTestId);
- rerender( );
+ rerender( );
const fallback = await findByTestId("fallback");
@@ -140,7 +136,7 @@ describe("ReactP5Wrapper", () => {
it.skip("Should show the default loading UI when the `loading` prop is not set and the sketch is not yet loaded", async () => {
const sketch = createSketch();
- const { findByTestId } = render( );
+ const { findByTestId } = render( );
const loading = await waitForLoading(findByTestId);
expect(loading).toBeInstanceOf(HTMLParagraphElement);
@@ -153,7 +149,7 @@ describe("ReactP5Wrapper", () => {
Loading test...
));
const { findByTestId } = render(
-
+
);
const loading = await waitForLoading(findByTestId);
@@ -162,16 +158,16 @@ describe("ReactP5Wrapper", () => {
expect(loading.innerHTML).toBe("Loading test...");
});
- it("Should show the default error UI when the `error` prop is not set an error is thrown within the subtree of the wrapper", async () => {
+ it("Should show the default error UI when the `error` prop is not set an error is thrown within the subtree of the canvas container", async () => {
const sketch = createSketch();
const ErrorChild = () => {
throw new Error("oops");
};
const { findByTestId } = render(
-
+
-
+
);
const error = await findByTestId("error");
@@ -180,7 +176,7 @@ describe("ReactP5Wrapper", () => {
expect(error.textContent).toBe("❌ - Something went wrong");
});
- it("Should show the error UI when the `error` prop is set an error is thrown within the subtree of the wrapper", async () => {
+ it("Should show the error UI when the `error` prop is set an error is thrown within the subtree of the canvas container", async () => {
const sketch = createSketch();
const ErrorView = vi.fn(error => {
assert(error instanceof Error);
@@ -192,9 +188,9 @@ describe("ReactP5Wrapper", () => {
};
const { findByTestId } = render(
-
+
-
+
);
const error = await findByTestId("error");
@@ -204,7 +200,7 @@ describe("ReactP5Wrapper", () => {
expect(error.innerHTML).toBe("Error: oops");
});
- it("Should log the error when an error is thrown within the subtree of the wrapper", async () => {
+ it("Should log the error when an error is thrown within the subtree of the canvas container", async () => {
const sketch = createSketch();
const ErrorView = vi.fn(() =>
);
const errorLogger = vi.fn();
@@ -216,9 +212,9 @@ describe("ReactP5Wrapper", () => {
};
const { findByTestId } = render(
-
+
-
+
);
await findByTestId("error");
@@ -226,7 +222,7 @@ describe("ReactP5Wrapper", () => {
expect(errorLoggerSpy).toHaveBeenCalledTimes(2);
expect(errorLoggerSpy).toHaveBeenCalledWith(
expect.stringContaining(
- "[ReactP5Wrapper] The error boundary was triggered. The error message was:"
+ "[P5Canvas] The error boundary was triggered. The error message was:"
)
);
expect(errorLoggerSpy).toHaveBeenCalledWith(
@@ -241,23 +237,21 @@ describe("ReactP5Wrapper", () => {
describe("Server", () => {
it("Renders as expected when using `renderToString`", () => {
const sketch = createSketch();
- const StringComponent = renderToString(
-
- );
+ const StringComponent = renderToString( );
expect(StringComponent).toBe(
- `
`
+ `
`
);
});
it("Renders as expected when using `renderToStaticMarkup`", () => {
const sketch = createSketch();
const StaticComponent = renderToStaticMarkup(
-
+
);
expect(StaticComponent).toBe(
- `
`
+ `
`
);
});
});
@@ -268,9 +262,7 @@ describe("ReactP5Wrapper", () => {
const updateFunction = vi.fn();
const sketch = createSketch(updateFunction);
- const { findByTestId } = render(
-
- );
+ const { findByTestId } = render( );
await waitForCanvas(findByTestId);
@@ -283,12 +275,12 @@ describe("ReactP5Wrapper", () => {
const updateFunction = vi.fn();
const sketch = createSketch(updateFunction);
const { rerender, findByTestId } = render(
-
+
);
await waitForCanvas(findByTestId);
- rerender( );
+ rerender( );
expect(sketch).toHaveBeenCalledOnce();
expect(updateFunction).toHaveBeenCalledTimes(2);
@@ -299,12 +291,12 @@ describe("ReactP5Wrapper", () => {
const updateFunction = vi.fn();
const sketch = createSketch(updateFunction);
const { rerender, findByTestId } = render(
-
+
);
await waitForCanvas(findByTestId);
- rerender( );
+ rerender( );
expect(sketch).toHaveBeenCalledOnce();
expect(updateFunction).toHaveBeenCalledTimes(2);
@@ -315,12 +307,12 @@ describe("ReactP5Wrapper", () => {
const updateFunction = vi.fn();
const sketch = createSketch(updateFunction);
const { rerender, findByTestId } = render(
-
+
);
await waitForCanvas(findByTestId);
- rerender( );
+ rerender( );
expect(sketch).toHaveBeenCalledOnce();
expect(updateFunction).toHaveBeenCalledTimes(2);
@@ -331,12 +323,12 @@ describe("ReactP5Wrapper", () => {
const updateFunction = vi.fn();
const sketch = createSketch(updateFunction);
const { rerender, findByTestId } = render(
-
+
);
await waitForCanvas(findByTestId);
- rerender( );
+ rerender( );
expect(sketch).toHaveBeenCalledOnce();
expect(updateFunction).toHaveBeenCalledTimes(2);
diff --git a/tests/constants/CanvasContainerClassName.test.ts b/tests/constants/CanvasContainerClassName.test.ts
new file mode 100644
index 0000000..bbe5c22
--- /dev/null
+++ b/tests/constants/CanvasContainerClassName.test.ts
@@ -0,0 +1,9 @@
+import { CanvasContainerClassName } from "@constants/CanvasContainerClassName";
+import { describe, expect, it } from "vitest";
+
+describe("CanvasContainerClassName", () => {
+ it("Is exported as a non-empty string", () => {
+ expect(CanvasContainerClassName).toBeTypeOf("string");
+ expect(CanvasContainerClassName.length).toBeGreaterThan(0);
+ });
+});
diff --git a/tests/constants/P5WrapperClassName.test.ts b/tests/constants/P5WrapperClassName.test.ts
deleted file mode 100644
index a7eb280..0000000
--- a/tests/constants/P5WrapperClassName.test.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { P5WrapperClassName } from "@constants/P5WrapperClassName";
-import { describe, expect, it } from "vitest";
-
-describe("P5WrapperClassName", () => {
- it("Is exported as a non-empty string", () => {
- expect(P5WrapperClassName).toBeTypeOf("string");
- expect(P5WrapperClassName.length).toBeGreaterThan(0);
- });
-});
diff --git a/tests/exports.test.tsx b/tests/exports.test.tsx
index 0c3fb97..6e3f463 100644
--- a/tests/exports.test.tsx
+++ b/tests/exports.test.tsx
@@ -1,27 +1,27 @@
-import { P5WrapperClassName, ReactP5Wrapper } from "@/main";
+import { CanvasContainerClassName, P5Canvas } from "@/main";
import { createElement, isValidElement } from "react";
import { assert, describe, expect, it, vi } from "vitest";
describe("Exports", () => {
- describe("P5WrapperClassName", () => {
- it("Exports the css class name used on the wrapper", () => {
- expect(P5WrapperClassName).not.toBeUndefined();
- expect(P5WrapperClassName).toBe("p5-wrapper-react");
+ describe("CanvasContainerClassName", () => {
+ it("Exports the css class name used on the canvas container", () => {
+ expect(CanvasContainerClassName).not.toBeUndefined();
+ expect(CanvasContainerClassName).toBe("canvas-container");
});
- it("Exports the css class name used on the wrapper as a non-empty string", () => {
- expect(typeof P5WrapperClassName).toBe("string");
- expect(P5WrapperClassName.length).toBeGreaterThan(0);
+ it("Exports the css class name used on the canvas container as a non-empty string", () => {
+ expect(typeof CanvasContainerClassName).toBe("string");
+ expect(CanvasContainerClassName.length).toBeGreaterThan(0);
});
- it("Exports the wrapper component", () => {
- expect(ReactP5Wrapper).not.toBeUndefined();
+ it("Exports the P5 canvas component", () => {
+ expect(P5Canvas).not.toBeUndefined();
});
});
- describe("ReactP5Wrapper", () => {
- it("Exports the wrapper component as a react element", () => {
- const component = createElement(ReactP5Wrapper, {
+ describe("P5Canvas", () => {
+ it("Exports the P5 canvas component as a React element", () => {
+ const component = createElement(P5Canvas, {
sketch: vi.fn()
});
diff --git a/tests/utils/createCanvasInstance.test.ts b/tests/utils/createCanvasInstance.test.ts
deleted file mode 100644
index aacd2e6..0000000
--- a/tests/utils/createCanvasInstance.test.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import p5 from "@contracts/p5";
-import { createCanvasInstance } from "@utils/createCanvasInstance";
-import { describe, expect, it, vi } from "vitest";
-
-describe("createCanvasInstance", () => {
- it("Should construct a valid implementation of p5 in instance mode", () => {
- const sketch = vi.fn();
- const wrapper = document.createElement("div");
- const instance = createCanvasInstance(sketch, wrapper);
-
- expect(instance).toBeInstanceOf(p5);
- });
-});
diff --git a/tests/utils/createP5CanvasInstance.test.ts b/tests/utils/createP5CanvasInstance.test.ts
new file mode 100644
index 0000000..c338ef2
--- /dev/null
+++ b/tests/utils/createP5CanvasInstance.test.ts
@@ -0,0 +1,13 @@
+import p5 from "@contracts/p5";
+import { createP5CanvasInstance } from "@utils/createP5CanvasInstance";
+import { describe, expect, it, vi } from "vitest";
+
+describe("createP5CanvasInstance", () => {
+ it("Should construct a valid implementation of p5 in instance mode", () => {
+ const sketch = vi.fn();
+ const canvasContainer = document.createElement("div");
+ const instance = createP5CanvasInstance(sketch, canvasContainer);
+
+ expect(instance).toBeInstanceOf(p5);
+ });
+});
diff --git a/tests/utils/logErrorBoundaryError.test.ts b/tests/utils/logErrorBoundaryError.test.ts
index 1894468..4288e93 100644
--- a/tests/utils/logErrorBoundaryError.test.ts
+++ b/tests/utils/logErrorBoundaryError.test.ts
@@ -31,7 +31,7 @@ describe("logErrorBoundaryError", () => {
expect(errorLoggerSpy).toHaveBeenCalledOnce();
expect(errorLoggerSpy).toHaveBeenCalledWith(
expect.stringContaining(
- "[ReactP5Wrapper] The error boundary was triggered. The error message was:"
+ "[P5Canvas] The error boundary was triggered. The error message was:"
)
);
expect(errorLoggerSpy).toHaveBeenCalledWith(
@@ -45,7 +45,7 @@ describe("logErrorBoundaryError", () => {
expect(errorLoggerSpy).toHaveBeenCalledOnce();
expect(errorLoggerSpy).toHaveBeenCalledWith(
expect.stringContaining(
- "[ReactP5Wrapper] The error boundary was triggered. The error message was:"
+ "[P5Canvas] The error boundary was triggered. The error message was:"
)
);
expect(errorLoggerSpy).toHaveBeenCalledWith(
@@ -59,7 +59,7 @@ describe("logErrorBoundaryError", () => {
expect(errorLoggerSpy).toHaveBeenCalledOnce();
expect(errorLoggerSpy).toHaveBeenCalledWith(
expect.stringContaining(
- "[ReactP5Wrapper] The error boundary was triggered. The error message was:"
+ "[P5Canvas] The error boundary was triggered. The error message was:"
)
);
expect(errorLoggerSpy).toHaveBeenCalledWith(
@@ -73,7 +73,7 @@ describe("logErrorBoundaryError", () => {
expect(errorLoggerSpy).toHaveBeenCalledOnce();
expect(errorLoggerSpy).toHaveBeenCalledWith(
expect.stringContaining(
- "[ReactP5Wrapper] The error boundary was triggered. The error message was:"
+ "[P5Canvas] The error boundary was triggered. The error message was:"
)
);
expect(errorLoggerSpy).toHaveBeenCalledWith(
@@ -87,7 +87,7 @@ describe("logErrorBoundaryError", () => {
expect(errorLoggerSpy).toHaveBeenCalledOnce();
expect(errorLoggerSpy).toHaveBeenCalledWith(
expect.stringContaining(
- "[ReactP5Wrapper] The error boundary was triggered. The error message was:"
+ "[P5Canvas] The error boundary was triggered. The error message was:"
)
);
expect(errorLoggerSpy).toHaveBeenCalledWith(
@@ -101,7 +101,7 @@ describe("logErrorBoundaryError", () => {
expect(errorLoggerSpy).toHaveBeenCalledOnce();
expect(errorLoggerSpy).toHaveBeenCalledWith(
expect.stringContaining(
- "[ReactP5Wrapper] The error boundary was triggered. The error message was:"
+ "[P5Canvas] The error boundary was triggered. The error message was:"
)
);
expect(errorLoggerSpy).toHaveBeenCalledWith(
@@ -115,7 +115,7 @@ describe("logErrorBoundaryError", () => {
expect(errorLoggerSpy).toHaveBeenCalledOnce();
expect(errorLoggerSpy).toHaveBeenCalledWith(
expect.stringContaining(
- "[ReactP5Wrapper] The error boundary was triggered. The error message was:"
+ "[P5Canvas] The error boundary was triggered. The error message was:"
)
);
expect(errorLoggerSpy).toHaveBeenCalledWith(
@@ -129,7 +129,7 @@ describe("logErrorBoundaryError", () => {
expect(errorLoggerSpy).toHaveBeenCalledOnce();
expect(errorLoggerSpy).toHaveBeenCalledWith(
expect.stringContaining(
- "[ReactP5Wrapper] The error boundary was triggered. The error message was:"
+ "[P5Canvas] The error boundary was triggered. The error message was:"
)
);
expect(errorLoggerSpy).toHaveBeenCalledWith(
@@ -143,7 +143,7 @@ describe("logErrorBoundaryError", () => {
expect(errorLoggerSpy).toHaveBeenCalledOnce();
expect(errorLoggerSpy).toHaveBeenCalledWith(
expect.stringContaining(
- "[ReactP5Wrapper] The error boundary was triggered. The error message was:"
+ "[P5Canvas] The error boundary was triggered. The error message was:"
)
);
expect(errorLoggerSpy).toHaveBeenCalledWith(
diff --git a/tests/utils/propsAreEqual.test.ts b/tests/utils/propsAreEqual.test.ts
index b5520ef..84bcf30 100644
--- a/tests/utils/propsAreEqual.test.ts
+++ b/tests/utils/propsAreEqual.test.ts
@@ -1,24 +1,24 @@
-import { type P5WrapperProps } from "@contracts/P5WrapperProps";
+import { type P5CanvasProps } from "@contracts/P5CanvasProps";
import { propsAreEqual } from "@utils/propsAreEqual";
import { describe, expect, it, vi } from "vitest";
describe("propsAreEqual", () => {
it("Returns true when the current and next props are the same", () => {
const sketch = vi.fn();
- const current: P5WrapperProps = { sketch };
- const next: P5WrapperProps = { sketch };
+ const current: P5CanvasProps = { sketch };
+ const next: P5CanvasProps = { sketch };
const equal = propsAreEqual(current, next);
expect(equal).toBe(true);
});
it("Returns false when the current and next props are not the same", () => {
- const current: P5WrapperProps = {
+ const current: P5CanvasProps = {
sketch: () => {
return;
}
};
- const next: P5WrapperProps = {
+ const next: P5CanvasProps = {
sketch: () => {
return;
}
diff --git a/tests/utils/removeCanvasInstance.test.ts b/tests/utils/removeCanvasInstance.test.ts
deleted file mode 100644
index cc85836..0000000
--- a/tests/utils/removeCanvasInstance.test.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { SketchProps } from "@/main";
-import { type CanvasInstanceRef } from "@contracts/CanvasInstanceRef";
-import p5 from "@contracts/p5";
-import { removeCanvasInstance } from "@utils/removeCanvasInstance";
-import { createRef } from "react";
-import { describe, expect, it, vi } from "vitest";
-
-describe("removeCanvasInstance", () => {
- it("Calls the remove method on the canvas if it exists", () => {
- const instance = new p5(() => {
- return;
- });
- const removeSpy = vi.spyOn(instance, "remove");
- const canvasInstanceRef: CanvasInstanceRef = createRef();
- canvasInstanceRef.current = instance;
-
- removeCanvasInstance(canvasInstanceRef);
-
- expect(removeSpy).toHaveBeenCalledOnce();
- });
-
- it("Sets the provided canvas instance ref to null", () => {
- const instance = new p5(() => {
- return;
- });
- const canvasInstanceRef: CanvasInstanceRef = createRef();
- canvasInstanceRef.current = instance;
-
- expect(canvasInstanceRef.current).not.toBeNull();
-
- removeCanvasInstance(canvasInstanceRef);
-
- expect(canvasInstanceRef.current).toBeNull();
- });
-});
diff --git a/tests/utils/removeP5CanvasInstance.test.ts b/tests/utils/removeP5CanvasInstance.test.ts
new file mode 100644
index 0000000..a49d6a3
--- /dev/null
+++ b/tests/utils/removeP5CanvasInstance.test.ts
@@ -0,0 +1,35 @@
+import { SketchProps } from "@/main";
+import p5 from "@contracts/p5";
+import { type P5CanvasInstanceRef } from "@contracts/P5CanvasInstanceRef";
+import { removeP5CanvasInstance } from "@utils/removeP5CanvasInstance";
+import { createRef } from "react";
+import { describe, expect, it, vi } from "vitest";
+
+describe("removeP5CanvasInstance", () => {
+ it("Calls the remove method on the P5 canvas instance if it exists", () => {
+ const instance = new p5(() => {
+ return;
+ });
+ const removeSpy = vi.spyOn(instance, "remove");
+ const p5CanvasInstanceRef: P5CanvasInstanceRef = createRef();
+ p5CanvasInstanceRef.current = instance;
+
+ removeP5CanvasInstance(p5CanvasInstanceRef);
+
+ expect(removeSpy).toHaveBeenCalledOnce();
+ });
+
+ it("Sets the provided P5 canvas instance ref to null", () => {
+ const instance = new p5(() => {
+ return;
+ });
+ const p5CanvasInstanceRef: P5CanvasInstanceRef = createRef();
+ p5CanvasInstanceRef.current = instance;
+
+ expect(p5CanvasInstanceRef.current).not.toBeNull();
+
+ removeP5CanvasInstance(p5CanvasInstanceRef);
+
+ expect(p5CanvasInstanceRef.current).toBeNull();
+ });
+});
diff --git a/tests/utils/updateCanvasInstance.test.ts b/tests/utils/updateCanvasInstance.test.ts
deleted file mode 100644
index e9a5faf..0000000
--- a/tests/utils/updateCanvasInstance.test.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import { SketchProps } from "@/main";
-import { type CanvasInstanceRef } from "@contracts/CanvasInstanceRef";
-import p5 from "@contracts/p5";
-import { type WrapperRef } from "@contracts/WrapperRef";
-import { createCanvasInstance } from "@utils/createCanvasInstance";
-import { updateCanvasInstance } from "@utils/updateCanvasInstance";
-import { createRef } from "react";
-import { describe, expect, it, vi } from "vitest";
-
-describe("updateCanvasInstance", () => {
- it("Should update a canvas instance to a new version", () => {
- const sketch = vi.fn();
- const wrapper = document.createElement("div");
- const wrapperRef: WrapperRef = createRef();
- const canvasInstanceRef: CanvasInstanceRef = createRef();
- const instance = createCanvasInstance(sketch, wrapper);
-
- wrapperRef.current = wrapper;
- canvasInstanceRef.current = instance;
-
- const updatedCanvasInstanceRef = updateCanvasInstance(
- canvasInstanceRef,
- wrapperRef,
- sketch
- );
-
- expect(instance).toBeInstanceOf(p5);
- expect(updatedCanvasInstanceRef).toBeInstanceOf(p5);
- expect(instance).not.toEqual(updatedCanvasInstanceRef);
- });
-
- it("Should return undefined if the wrapperRef value is null", () => {
- const sketch = vi.fn();
- const wrapper = document.createElement("div");
- const wrapperRef: WrapperRef = createRef();
- const canvasInstanceRef: CanvasInstanceRef = createRef();
- const instance = createCanvasInstance(sketch, wrapper);
-
- canvasInstanceRef.current = instance;
-
- const updatedCanvasInstanceRef = updateCanvasInstance(
- canvasInstanceRef,
- wrapperRef,
- sketch
- );
-
- expect(updatedCanvasInstanceRef).toBeNull();
- });
-});
diff --git a/tests/utils/updateP5CanvasInstance.test.ts b/tests/utils/updateP5CanvasInstance.test.ts
new file mode 100644
index 0000000..7fc3e2c
--- /dev/null
+++ b/tests/utils/updateP5CanvasInstance.test.ts
@@ -0,0 +1,49 @@
+import { SketchProps } from "@/main";
+import { type CanvasContainerRef } from "@contracts/CanvasContainerRef";
+import p5 from "@contracts/p5";
+import { type P5CanvasInstanceRef } from "@contracts/P5CanvasInstanceRef";
+import { createP5CanvasInstance } from "@utils/createP5CanvasInstance";
+import { updateP5CanvasInstance } from "@utils/updateP5CanvasInstance";
+import { createRef } from "react";
+import { describe, expect, it, vi } from "vitest";
+
+describe("updateP5CanvasInstance", () => {
+ it("Should update a P5 canvas instance to a new version", () => {
+ const sketch = vi.fn();
+ const canvasContainer = document.createElement("div");
+ const canvasContainerRef: CanvasContainerRef = createRef();
+ const p5CanvasInstanceRef: P5CanvasInstanceRef = createRef();
+ const instance = createP5CanvasInstance(sketch, canvasContainer);
+
+ canvasContainerRef.current = canvasContainer;
+ p5CanvasInstanceRef.current = instance;
+
+ const updatedP5CanvasInstanceRef = updateP5CanvasInstance(
+ p5CanvasInstanceRef,
+ canvasContainerRef,
+ sketch
+ );
+
+ expect(instance).toBeInstanceOf(p5);
+ expect(updatedP5CanvasInstanceRef).toBeInstanceOf(p5);
+ expect(instance).not.toEqual(updatedP5CanvasInstanceRef);
+ });
+
+ it("Should return undefined if the canvasContainerRef value is null", () => {
+ const sketch = vi.fn();
+ const canvasContainer = document.createElement("div");
+ const canvasContainerRef: CanvasContainerRef = createRef();
+ const p5CanvasInstanceRef: P5CanvasInstanceRef = createRef();
+ const instance = createP5CanvasInstance(sketch, canvasContainer);
+
+ p5CanvasInstanceRef.current = instance;
+
+ const updatedP5CanvasInstanceRef = updateP5CanvasInstance(
+ p5CanvasInstanceRef,
+ canvasContainerRef,
+ sketch
+ );
+
+ expect(updatedP5CanvasInstanceRef).toBeNull();
+ });
+});