picobook/src/client/pico8-client/Pico8Console.tsx

85 lines
2.0 KiB
TypeScript
Raw Normal View History

2024-03-31 12:13:27 -07:00
import { css } from "@emotion/css";
import { PicoCart, PicoPlayerHandle, makePicoConsole } from "./renderCart";
import { ForwardedRef, forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react";
type Pico8ConsoleImperatives = {
getPicoConsoleHandle(): PicoPlayerHandle | null;
}
export const Pico8Console = forwardRef((props: { carts: PicoCart[] }, forwardedRef: ForwardedRef<Pico8ConsoleImperatives>) => {
const {carts} = props;
2024-03-31 20:37:18 -07:00
const [playing, setPlaying] = useState(false);
2024-03-31 12:13:27 -07:00
const ref = useRef<HTMLDivElement>(null);
const [handle, setHandle] = useState<PicoPlayerHandle | null>(null);
const attachConsole = useCallback(async () => {
const picoConsole = await makePicoConsole({
carts,
});
2024-04-01 00:22:52 -07:00
picoConsole.canvas.tabIndex=0;
2024-03-31 12:13:27 -07:00
if (ref.current) {
ref.current.appendChild(picoConsole.canvas);
2024-04-01 00:22:52 -07:00
picoConsole.canvas.focus();
2024-03-31 12:13:27 -07:00
}
setHandle(picoConsole);
2024-04-01 00:22:52 -07:00
picoConsole.canvas.addEventListener('keydown',(event) => {
if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(event.key)) {
event.preventDefault();
2024-03-31 21:25:54 -07:00
}
2024-04-01 00:22:52 -07:00
}, {passive: false});
picoConsole.canvas.addEventListener('click', () => {
picoConsole.canvas.focus();
})
2024-03-31 12:13:27 -07:00
}, [carts]);
useImperativeHandle(forwardedRef, () => ({
getPicoConsoleHandle() {
return handle;
}
}), [handle]);
useEffect(() => {
2024-04-01 00:22:52 -07:00
if (playing) {
2024-03-31 20:37:18 -07:00
attachConsole();
return () => {
if (ref.current) {
ref.current.innerHTML = "";
}
}
}
}, [playing, attachConsole]);
if (!playing) {
return (
<div
ref={ref}
className={css`
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
aspect-ratio: 1;
background-color: black;
color: white;
cursor: pointer;
`}
2024-04-01 00:22:52 -07:00
tabIndex={0}
onClick={() => {setPlaying(true)}}
2024-03-31 20:37:18 -07:00
>
Play!
</div>
)
}
2024-03-31 12:13:27 -07:00
return (
<div ref={ref} className={css`
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
& > canvas {
width: 100%;
height: 100%;
}
`}></div>
);
});