Skip to content

Commit 17aa053

Browse files
committed
Update children interactions (#168)
* Add example using a rotating plane * Cover and error for the runtime issue when a sketch is not provided * Update dependencies * Update logic to actually throw rather than log until a workaround for the hook execution order is found * Document how to handle the styling / positioning of children with a working example
1 parent b965e6a commit 17aa053

21 files changed

+10529
-24149
lines changed

.github/workflows/MASTER_PULL_REQUEST.yml

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,37 @@ jobs:
1414

1515
- uses: actions/setup-node@v2
1616
with:
17-
node-version: "16"
17+
node-version: 16
1818

19-
- uses: c-hive/gha-npm-cache@v1
19+
- uses: pnpm/action-setup@v2.0.1
20+
name: Install pnpm
21+
id: pnpm-install
22+
with:
23+
version: 7
24+
run_install: false
25+
26+
- name: Get pnpm store directory
27+
id: pnpm-cache
28+
run: |
29+
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
30+
31+
- uses: actions/cache@v3
32+
name: Setup pnpm cache
33+
with:
34+
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
35+
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
36+
restore-keys: |
37+
${{ runner.os }}-pnpm-store-
2038
2139
- name: Install dependencies
22-
run: npm ci
40+
run: pnpm install
2341

2442
- name: Check formatting
25-
run: npm run format:check
43+
run: pnpm format:check
2644

2745
- name: Formatting issues detected (attempting fix...)
2846
if: ${{ failure() }}
29-
run: npm run format
47+
run: pnpm format
3048

3149
- name: Commit fixed formatting issues
3250
uses: stefanzweifel/git-auto-commit-action@v4
@@ -35,11 +53,11 @@ jobs:
3553
branch: ${{ github.head_ref }}
3654

3755
- name: Lint
38-
run: npm run lint
56+
run: pnpm lint
3957

4058
- name: Linting issues detected (attempting fix...)
4159
if: ${{ failure() }}
42-
run: npm run lint:fix
60+
run: pnpm lint:fix
4361

4462
- name: Commit fixed linting issues
4563
uses: stefanzweifel/git-auto-commit-action@v4
@@ -48,7 +66,7 @@ jobs:
4866
branch: ${{ github.head_ref }}
4967

5068
- name: Test
51-
run: npm run test
69+
run: pnpm test
5270

5371
- name: Build
54-
run: npm run build
72+
run: pnpm build

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
coverage
33
node_modules
44
dist
5-
.DS_Store
5+
.DS_Store
6+
package-lock.json

README.md

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ Then just open `http://localhost:3001` in a browser.
3434
npm install react-p5-wrapper
3535
```
3636

37+
### PNPM
38+
39+
```sh
40+
pnpm add react-p5-wrapper
41+
```
42+
3743
### Yarn
3844

3945
```sh
@@ -368,8 +374,64 @@ export function App() {
368374

369375
### Children
370376

371-
To render a component on top of the sketch, simply add it as a child of the
372-
`ReactP5Wrapper` component.
377+
To render a component on top of the sketch, you can add it as a child of the
378+
`ReactP5Wrapper` component and then use the exported `P5WrapperClassName`
379+
constant in your to style one element above the other via css.
380+
381+
For instance, using [styled components](https://styled-components.com), we could
382+
center some text on top of our sketch like so:
383+
384+
```jsx
385+
import { ReactP5Wrapper, P5WrapperClassName } from "../src/index.tsx";
386+
import styled, { createGlobalStyle } from "styled-components";
387+
388+
const GlobalWrapperStyles = createGlobalStyle`
389+
.${P5WrapperClassName} {
390+
position: relative;
391+
}
392+
`;
393+
394+
const StyledCentredText = styled.span`
395+
.${P5WrapperClassName} & {
396+
position: absolute;
397+
top: 50%;
398+
left: 50%;
399+
transform: translate(-50%, -50%);
400+
color: white;
401+
font-size: 2rem;
402+
margin: 0;
403+
text-align: center;
404+
}
405+
`;
406+
407+
export function App() {
408+
const [rotation, setRotation] = useState(0);
409+
410+
useEffect(() => {
411+
const interval = setInterval(
412+
() => setRotation(rotation => rotation + 100),
413+
100
414+
);
415+
416+
return () => {
417+
clearInterval(interval);
418+
};
419+
}, []);
420+
421+
return (
422+
<Fragment>
423+
<GlobalWrapperStyles />
424+
<ReactP5Wrapper sketch={sketch} rotation={rotation}>
425+
<StyledCentredText>Hello world!</StyledCentredText>
426+
</ReactP5Wrapper>
427+
</Fragment>
428+
);
429+
}
430+
```
431+
432+
Of course you can also use any other css-in-js library or by just using simple
433+
css to achieve almost anything you can imagine just by using the wrapper class
434+
as your root selector.
373435

374436
## Development
375437

File renamed without changes.
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
const { join } = require("path");
22

33
module.exports = {
4-
rootDir: "..",
4+
rootDir: join(__dirname, "..", ".."),
55
silent: true,
6-
testEnvironment: "jsdom",
76
testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
87
transform: {
98
"^.+\\.tsx?$": "ts-jest"
109
},
1110
moduleFileExtensions: ["ts", "tsx", "js", "jsx"],
1211
globals: {
1312
"ts-jest": {
14-
tsconfig: join(__dirname, "tsconfig.json")
13+
tsconfig: join(__dirname, "..", "typescript", "tsconfig.json")
1514
}
16-
}
15+
},
16+
testEnvironment: join(__dirname, "jest.environment.js")
1717
};

config/jest/jest.environment.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
const Environment = require("jest-environment-jsdom-global");
2+
const { TextEncoder, TextDecoder } = require("util");
3+
4+
class CustomTestEnvironment extends Environment {
5+
async setup() {
6+
await super.setup();
7+
this.polyfillTextEncoder();
8+
this.polyfillTextDecoder();
9+
}
10+
11+
polyfillTextEncoder() {
12+
if (typeof this.global.TextEncoder !== "undefined") {
13+
return;
14+
}
15+
16+
this.global.TextEncoder = TextEncoder;
17+
}
18+
19+
polyfillTextDecoder() {
20+
if (typeof this.global.TextDecoder !== "undefined") {
21+
return;
22+
}
23+
24+
this.global.TextDecoder = TextDecoder;
25+
}
26+
}
27+
28+
module.exports = CustomTestEnvironment;
File renamed without changes.

config/rollup.config.js renamed to config/rollup/rollup.config.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
import typescript from "rollup-plugin-typescript2";
22
import { terser } from "rollup-plugin-terser";
3-
import { dependencies, peerDependencies, module, main } from "../package.json";
3+
import {
4+
dependencies,
5+
peerDependencies,
6+
module,
7+
main
8+
} from "../../package.json";
49
import { join } from "path";
510

6-
const input = "src/index.tsx";
11+
const input = join(__dirname, "..", "..", "src", "index.tsx");
712
const external = [
813
...Object.keys(dependencies ?? {}),
914
...Object.keys(peerDependencies ?? {})
1015
];
1116
const plugins = [
1217
typescript({
1318
typescript: require("typescript"),
14-
tsconfig: join(__dirname, "tsconfig.json")
19+
tsconfig: join(__dirname, "..", "typescript", "tsconfig.json")
1520
}),
1621
terser({
1722
format: {

config/tsconfig.json renamed to config/typescript/tsconfig.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"compilerOptions": {
3-
"outDir": "../dist",
3+
"outDir": "../../dist",
44
"declaration": true,
55
"esModuleInterop": true,
66
"forceConsistentCasingInFileNames": true,
@@ -11,5 +11,5 @@
1111
"target": "es5",
1212
"moduleResolution": "node"
1313
},
14-
"include": ["../src/**/*"]
14+
"include": ["../../src/**/*"]
1515
}

config/webpack.config.js renamed to config/webpack/webpack.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const { join } = require("path");
22
const HtmlWebpackPlugin = require("html-webpack-plugin");
33

4-
const BASE_DIR = join(__dirname, "..");
4+
const BASE_DIR = join(__dirname, "..", "..");
55
const DISTRIBUTION_DIRECTORY = join(BASE_DIR, "dist", "demo");
66
const EXAMPLE_DIRECTORY = join(BASE_DIR, "example");
77

@@ -22,7 +22,7 @@ module.exports = (env, options) => {
2222
test: /\.tsx?$/,
2323
loader: "ts-loader",
2424
options: {
25-
configFile: join(__dirname, "tsconfig.json")
25+
configFile: join(__dirname, "..", "typescript", "tsconfig.json")
2626
}
2727
},
2828
{

example/app.jsx

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,48 @@
1-
import React, { Fragment, useState, useCallback } from "react";
1+
import React, { Fragment, useState, useCallback, useMemo } from "react";
22
import { render } from "react-dom";
33
import { ReactP5Wrapper } from "../src/index.tsx";
44
import * as box from "./sketches/box";
55
import * as torus from "./sketches/torus";
6+
import * as plane from "./sketches/plane";
67
import "./example.css";
78

89
function App() {
10+
const sketches = useMemo(
11+
() => [box.sketch, torus.sketch, plane.sketch],
12+
[box, torus, plane]
13+
);
914
const [state, setState] = useState({
1015
rotation: 160,
1116
sketch: box.sketch,
1217
unmount: false
1318
});
1419
const onChangeSketch = useCallback(() => {
15-
const useTorus = state.sketch === box.sketch;
16-
const sketch = useTorus ? torus.sketch : box.sketch;
20+
setState(state => {
21+
const currentSketchIndex = sketches.findIndex(sketch => {
22+
return Object.is(sketch, state.sketch);
23+
});
24+
const nextSketchIndex = (currentSketchIndex + 1) % sketches.length;
25+
const sketch = sketches.at(nextSketchIndex);
1726

18-
setState(state => ({ ...state, sketch }));
19-
}, [state.sketch, box.sketch, torus.sketch]);
20-
const onChangeRotation = useCallback(event => {
21-
setState(state => ({
22-
...state,
23-
rotation: parseInt(event.target.value, 10)
24-
}));
25-
}, []);
27+
if (sketch === undefined) {
28+
return state;
29+
}
30+
31+
return { ...state, sketch };
32+
});
33+
}, [sketches]);
2634
const onMountStateChange = useCallback(() => {
2735
setState(state => ({ ...state, unmount: !state.unmount }));
2836
}, []);
37+
const onRotationChange = useCallback(
38+
event => {
39+
setState(state => ({
40+
...state,
41+
rotation: parseInt(event.target.value, 10)
42+
}));
43+
},
44+
[box, plane, torus]
45+
);
2946

3047
if (state.unmount) {
3148
return (
@@ -45,7 +62,7 @@ function App() {
4562
min="0"
4663
max="360"
4764
step="1"
48-
onChange={onChangeRotation}
65+
onChange={onRotationChange}
4966
/>
5067
<button onClick={onChangeSketch}>Change Sketch</button>
5168
<button onClick={onMountStateChange}>Unmount</button>

example/index.html

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,17 @@ <h2>
1010
</h2>
1111
<div id="app"></div>
1212
<div class="footer">
13-
Copyright &copy; 2016 -
14-
<script>
15-
new Date().getFullYear() > 2016 &&
16-
document.write(new Date().getFullYear());
17-
</script>
13+
Copyright &copy; 2016 - <span id="currentYear"></span>
1814
<a href="https://github.com/P5-wrapper/react/graphs/contributors"
1915
>Contributors</a
2016
>.
2117
</div>
18+
<script>
19+
if (new Date().getFullYear() > 2016) {
20+
document.getElementById("currentYear").textContent = new Date()
21+
.getFullYear()
22+
.toString();
23+
}
24+
</script>
2225
</div>
2326
</body>

example/sketches/box.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export function sketch(p5) {
1515
p5.noStroke();
1616

1717
p5.push();
18-
p5.translate(-40, 50);
18+
p5.translate(-35, 0);
1919
p5.rotateY(rotation);
2020
p5.rotateX(-0.9);
2121
p5.box(100);

example/sketches/plane.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
export function sketch(p5) {
2+
let rotation = 0;
3+
4+
p5.setup = () => p5.createCanvas(300, 300, p5.WEBGL);
5+
6+
p5.updateWithProps = props => {
7+
if (props.rotation) {
8+
rotation = (props.rotation * Math.PI) / 180;
9+
}
10+
};
11+
12+
p5.draw = () => {
13+
p5.background(100);
14+
p5.normalMaterial();
15+
16+
p5.push();
17+
p5.rotateZ(rotation);
18+
p5.rotateX(rotation);
19+
p5.rotateY(rotation);
20+
p5.plane(100);
21+
p5.pop();
22+
};
23+
}

0 commit comments

Comments
 (0)