Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version 5.0.0-rc.0 #325

Merged
merged 20 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ pnpm-lock.yaml
*.njsproj
*.sln
*.sw?
tsconfig.tsbuildinfo
115 changes: 112 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ instead use
To do get started, you can run:

```shell
[npm|yarn|pnpm] [install|add] @p5-wrapper/next @p5-wrapper/react
[npm|yarn|pnpm] [install|add] p5 @p5-wrapper/next @p5-wrapper/react
```

Please continue reading these docs and also look at
Expand Down Expand Up @@ -50,7 +50,7 @@ To install, use the following command in the format appropriate to your chosen
package manager:

```shell
[npm|yarn|pnpm] [install|add] @p5-wrapper/react
[npm|yarn|pnpm] [install|add] p5 @p5-wrapper/react
```

## Usage
Expand Down Expand Up @@ -441,7 +441,7 @@ 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.

## Fallback UIs
### Fallback UIs

Lets say you want to have a fallback UI in case the `sketch` ever falls out of
sync or is undefined for some reason. If this is a use case for you then you
Expand Down Expand Up @@ -515,6 +515,115 @@ In this case, by default the fallback UI containing
sketch, it will be rendered until you choose to once again "show nothing" which
falls back to the fallback UI.

### Error and Loading UIs

Since version 4.4.0, it was possible to add a `fallback` prop, see the section
on fallbacks.

Since version 5 it is now possible to pass an `error` and `loading` prop to the
wrapper which allow the user to pass different UIs for error and loading states.

- The `error` state will trigger if the sketch or the wrapper encounter an
issue, otherwise a default error view will be shown.
- The `loading` state will trigger while the wrapper is being lazy loaded,
otherwise a default loading view will be shown.

#### Error UIs

To show a custom UI when an error occurs within the sketch or the wrapper, you
can pass a lazy function to the `error` prop.

```tsx
import * as React from "react";
import { P5CanvasInstance, ReactP5Wrapper } 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 <p>An error occured: {error.message}</p>;
}

return <p>An unknown error occured: {error.toString()}</p>;
}

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 (
<ReactP5Wrapper sketch={sketch} error={ErrorUI}>
<ErrorChild />
</ReactP5Wrapper>
);
}
```

Instead of the sketch, this will render `<p>An error occured: oops</p>`. 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
the `error instanceof Error` check to be sure the value we got was actually an
`Error` instance and not some other value like a `number`, `string`, `object` or
anything else that could be thrown by JS / TS.

As mentioned above, the `error` state will trigger if the sketch or the wrapper
encounter an issue, otherwise a default error view will be shown.

#### Loading UIs

To show a custom UI while the sketch UI is being lazy loaded, you can pass a
lazy function to the `loading` prop.

```tsx
import * as React from "react";
import { P5CanvasInstance, ReactP5Wrapper } from "@p5-wrapper/react";

function LoadingUI() {
return <p>The sketch is being loaded.</p>;
}

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 <ReactP5Wrapper sketch={sketch} loading={LoadingUI} />;
}
```

In the initial period between the sketch render starting and it's lazy loading
ending, the `LoadingUI` will be shown!

As mentioned above, the `loading` state will trigger while the wrapper is being
lazy loaded, otherwise a default loading view will be shown.

## P5 plugins and constructors

As discussed in multiple issues such as
Expand Down
24 changes: 24 additions & 0 deletions config/eslint/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import eslint from "@eslint/js";
import reactCompiler from "eslint-plugin-react-compiler";
import { dirname } from "path";
import tseslint from "typescript-eslint";

export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommended,
{
languageOptions: {
parserOptions: {
project: true,
tsconfigRootDir: dirname(dirname(import.meta.dirname))
}
},
ignores: [path => path.includes("dist")],
plugins: {
"react-compiler": reactCompiler
},
rules: {
"react-compiler/react-compiler": "error"
}
}
);
25 changes: 0 additions & 25 deletions config/eslint/eslint.json

This file was deleted.

7 changes: 4 additions & 3 deletions config/typescript/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"compilerOptions": {
"outDir": "../../dist/component",
"target": "ESNext",
"composite": true,
"useDefineForClassFields": true,
"types": ["vite/client"],
"lib": ["DOM", "DOM.Iterable", "ESNext"],
Expand All @@ -16,8 +16,9 @@
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": false,
"jsx": "react-jsx"
"jsx": "react-jsx",
"noImplicitAny": true
},
"include": ["../../src"],
"include": ["../../"],
"references": [{ "path": "./tsconfig.node.json" }]
}
50 changes: 41 additions & 9 deletions config/vite/vite.component.config.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,64 @@
import react from "@vitejs/plugin-react";
import { resolve } from "node:path";
import { splitVendorChunkPlugin } from "vite";
import dts from "vite-plugin-dts";
import { defineConfig } from "vitest/config";

// noinspection JSUnusedGlobalSymbols
const outputDirectory = resolve(__dirname, "..", "..", "dist", "component");

export default defineConfig({
plugins: [splitVendorChunkPlugin(), react()],
plugins: [
dts({
rollupTypes: true,
outDir: outputDirectory
}),
react({
babel: {
plugins: [["babel-plugin-react-compiler", {}]]
}
})
],
esbuild: {
legalComments: "external"
},
build: {
emptyOutDir: false,
emptyOutDir: true,
lib: {
entry: resolve(__dirname, "..", "..", "src", "main.tsx"),
name: "ReactP5Wrapper"
name: "ReactP5Wrapper",
fileName: "ReactP5Wrapper",
formats: ["es", "cjs"]
},
rollupOptions: {
external: ["react", "react-dom"],
external: ["react", "react/jsx-runtime", "react-dom", "p5"],
output: {
dir: resolve(__dirname, "..", "..", "dist", "component"),
assetFileNames: "assets/[name][extname]",
entryFileNames: "[name].[format].js",
dir: outputDirectory,
globals: {
p5: "p5",
react: "React",
"react/jsx-runtime": "jsxRuntime",
"react-dom": "ReactDom"
}
}
}
},
test: {
globals: true,
threads: false,
environment: "jsdom",
setupFiles: resolve(__dirname, "..", "..", "tests", "setup.ts")
coverage: {
include: ["src"]
},
setupFiles: resolve(__dirname, "..", "..", "tests", "setup.ts"),
deps: {
optimizer: {
web: {
include: ["vitest-canvas-mock"]
}
}
},
onConsoleLog() {
return false;
}
}
});
1 change: 0 additions & 1 deletion config/vite/vite.demo.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import react from "@vitejs/plugin-react";
import { resolve } from "node:path";
import { defineConfig } from "vitest/config";

// noinspection JSUnusedGlobalSymbols
export default defineConfig({
root: resolve(__dirname, "..", "..", "demo"),
base: "./",
Expand Down
10 changes: 5 additions & 5 deletions demo/app.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { Fragment, useCallback, useMemo, useState } from "react";
import React, { useCallback, useMemo, useState } from "react";
import { createRoot } from "react-dom/client";

import * as box from "./sketches/box";
Expand Down Expand Up @@ -47,15 +47,15 @@ function App() {

if (state.unmount) {
return (
<Fragment>
<>
<p>Unmounted the sketch</p>
jamesrweb marked this conversation as resolved.
Show resolved Hide resolved
<button onClick={onMountStateChange}>Remount</button>
</Fragment>
</>
);
}

return (
<Fragment>
<>
<ReactP5Wrapper sketch={state.sketch} rotation={state.rotation} />
<input
type="range"
Expand All @@ -67,7 +67,7 @@ function App() {
/>
<button onClick={onChangeSketch}>Change Sketch</button>
<button onClick={onMountStateChange}>Unmount</button>
</Fragment>
</>
);
}

Expand Down
Loading
Loading