Enforce functions (#625)

This commit is contained in:
Corwin 2024-04-09 20:22:28 +01:00 committed by GitHub
commit 646b7947e9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 95 additions and 74 deletions

View file

@ -1,3 +1,6 @@
{
"extends": "next/core-web-vitals"
"extends": "next/core-web-vitals",
"rules": {
"func-style": ["error", "declaration", {"allowArrowFunctions": false}]
}
}

View file

@ -32,12 +32,18 @@ const InnerBlock = styled.div<{ $centered?: boolean }>`
margin-bottom: 40px;
`;
export const ContentBlock: FC<{
export function ContentBlock({
color = "",
children,
uncentered = false,
}: {
color?: string;
uncentered?: boolean;
children: ReactNode;
}> = ({ color = "", children, uncentered = false }) => (
}) {
return (
<Section $color={color}>
<InnerBlock $centered={!uncentered}>{children}</InnerBlock>
</Section>
);
}

View file

@ -10,9 +10,11 @@ const BacktraceWrapper = styled.section`
justify-content: center;
`;
const getBacktrace = () => window.location.hash.slice(1);
function getBacktrace() {
return window.location.hash.slice(1);
}
export const BacktraceDisplay: FC = () => {
export function BacktraceDisplay() {
const backtrace = useClientValue(getBacktrace) ?? "";
return (
@ -28,4 +30,4 @@ export const BacktraceDisplay: FC = () => {
</button>
</BacktraceWrapper>
);
};
}

View file

@ -34,15 +34,15 @@ export function Slider({
}) {
const slider = useRef<HTMLDivElement>(null);
const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {
function handleClick(event: React.MouseEvent<HTMLDivElement>) {
onChange(
event.nativeEvent.offsetX / (event.target as HTMLDivElement).offsetWidth
);
event.stopPropagation();
};
}
const handleDrag = (event: React.MouseEvent<HTMLDivElement>) => {
function handleDrag(event: React.MouseEvent<HTMLDivElement>) {
const sliderRef = slider.current;
if (!sliderRef || event.buttons !== 1) {
@ -56,7 +56,7 @@ export function Slider({
const clamped = Math.min(1, Math.max(0, proportion));
onChange(clamped);
};
}
return (
<SliderWrapper ref={slider} onClick={handleClick} onMouseMove={handleDrag}>

View file

@ -1,7 +1,7 @@
import { FC, useState } from "react";
import styled from "styled-components";
const DefaultBindings = (): KeyBindings => {
function DefaultBindings(): KeyBindings {
return {
A: "Z",
B: "X",
@ -14,12 +14,14 @@ const DefaultBindings = (): KeyBindings => {
Left: "LEFT",
Right: "RIGHT",
};
};
}
export const DefaultBindingsSet = (): Bindings => ({
export function DefaultBindingsSet(): Bindings {
return {
Actual: DefaultBindings(),
Displayed: DefaultBindings(),
});
};
}
export enum GbaKey {
A = "A",
@ -69,18 +71,22 @@ export interface Bindings {
Actual: KeyBindings;
}
const toHumanName = (keyName: string) => {
function toHumanName(keyName: string) {
return keyName.replace("Arrow", "");
};
}
export const BindingsControl: FC<{
export function BindingsControl({
bindings,
setBindings,
setPaused,
}: {
bindings: Bindings;
setBindings: (a: Bindings) => void;
setPaused: (pause: boolean) => void;
}> = ({ bindings, setBindings, setPaused }) => {
}) {
const [buttonToChange, setButtonToChange] = useState<GbaKey | null>(null);
const setKey = (key: string) => {
function setKey(key: string) {
if (buttonToChange === null) return;
const nextBindings = {
@ -94,12 +100,12 @@ export const BindingsControl: FC<{
setButtonToChange(null);
setBindings(nextBindings);
setPaused(false);
};
}
const onSelectButtonClick = (key: GbaKey) => {
function onSelectButtonClick(key: GbaKey) {
setPaused(true);
setButtonToChange(key);
};
}
return (
<ButtonWrapper onKeyUp={(evt: React.KeyboardEvent) => setKey(evt.key)}>
@ -116,4 +122,4 @@ export const BindingsControl: FC<{
))}
</ButtonWrapper>
);
};
}

View file

@ -41,7 +41,7 @@ export interface MgbaHandle {
buttonRelease: (key: GbaKey) => void;
}
const downloadGame = async (gameUrl: string): Promise<ArrayBuffer> => {
async function downloadGame(gameUrl: string): Promise<ArrayBuffer> {
const game = await fetch(gameUrl);
if (gameUrl.endsWith(".gz")) {
@ -52,7 +52,7 @@ const downloadGame = async (gameUrl: string): Promise<ArrayBuffer> => {
} else {
return await game.arrayBuffer();
}
};
}
export const Mgba = forwardRef<MgbaHandle, MgbaProps>(
({ gameUrl, volume, controls, paused }, ref) => {

View file

@ -65,11 +65,13 @@ interface MgbaWrapperProps {
setIsPlaying?: (isPlaying: boolean) => void;
}
export const MgbaStandalone: FC<MgbaWrapperProps> = (props) => (
export function MgbaStandalone(props: MgbaWrapperProps) {
return (
<AppContainer>
<MgbaWrapper {...props} />
</AppContainer>
);
}
export const MgbaWrapper = forwardRef<MgbaHandle, MgbaWrapperProps>(
({ gameUrl, isPlaying = true, setIsPlaying }, ref) => {
@ -80,10 +82,12 @@ export const MgbaWrapper = forwardRef<MgbaHandle, MgbaWrapperProps>(
const [mgbaId, setMgbaId] = useState(0);
const setVolume = (newVolume: number) =>
setState({ volume: newVolume, bindings });
const setBindings = (newBindings: Bindings) =>
setState({ volume, bindings: newBindings });
function setVolume(newVolume: number) {
return setState({ volume: newVolume, bindings });
}
function setBindings(newBindings: Bindings) {
return setState({ volume, bindings: newBindings });
}
const [paused, setPaused] = useState(false);

View file

@ -1,12 +1,12 @@
import { useEffect } from "react";
export const useAvoidItchIoScrolling = () => {
export function useAvoidItchIoScrolling() {
useEffect(() => {
const eventHandler = (e: KeyboardEvent) => {
function eventHandler(e: KeyboardEvent) {
if ([32, 37, 38, 39, 40].indexOf(e.keyCode) > -1) {
e.preventDefault();
}
};
}
window.addEventListener("keydown", eventHandler, false);
@ -14,4 +14,4 @@ export const useAvoidItchIoScrolling = () => {
window.removeEventListener("keydown", eventHandler, false);
};
}, []);
};
}

View file

@ -2,7 +2,7 @@ import { MutableRefObject, useEffect } from "react";
import { mGBAEmulator } from "./vendor/mgba";
export const useFrameSkip = (mgbaModule: MutableRefObject<mGBAEmulator>) => {
export function useFrameSkip(mgbaModule: MutableRefObject<mGBAEmulator>) {
useEffect(() => {
let previous: number | undefined = undefined;
let stopped = false;
@ -11,7 +11,7 @@ export const useFrameSkip = (mgbaModule: MutableRefObject<mGBAEmulator>) => {
let totalTime = 0;
let paused = false;
const raf = (time: DOMHighResTimeStamp) => {
function raf(time: DOMHighResTimeStamp) {
if (previous) {
const delta = time - previous;
@ -45,7 +45,7 @@ export const useFrameSkip = (mgbaModule: MutableRefObject<mGBAEmulator>) => {
}
window.requestAnimationFrame(raf);
return () => { stopped = true; }
return () => { stopped = true; };
}, [mgbaModule]);

View file

@ -1,9 +1,7 @@
import { useCallback, useState } from "react";
export const useLocalStorage = <T>(
defaultValue: T,
appName: string
): [T, (newValue: T) => void] => {
export function useLocalStorage<T>(defaultValue: T,
appName: string): [T, (newValue: T) => void] {
const [value, setValue] = useState(() => {
try {
const storageValue = localStorage.getItem(appName);
@ -26,4 +24,4 @@ export const useLocalStorage = <T>(
}, []);
return [value, setStoredValue];
};
}

View file

@ -1,12 +1,12 @@
import { useEffect } from "react";
export const useOnKeyUp = (targetKey: string, callback: () => void) => {
export function useOnKeyUp(targetKey: string, callback: () => void) {
useEffect(() => {
const downHandler = (evnt: KeyboardEvent) => {
function downHandler(evnt: KeyboardEvent) {
if (evnt.key === targetKey) {
callback();
}
};
}
window.addEventListener("keyup", downHandler);
@ -14,4 +14,4 @@ export const useOnKeyUp = (targetKey: string, callback: () => void) => {
window.removeEventListener("keyup", downHandler);
};
}, [callback, targetKey]);
};
}

View file

@ -52,7 +52,7 @@ const MobileControlsRow = styled.div<{
${(props) => props.$centered && `justify-content: center;`}
`;
const useSimpleButton = (mgba: MgbaHandle, button: GbaKey) => {
function useSimpleButton(mgba: MgbaHandle, button: GbaKey) {
return useMemo(() => {
return {
onTouchStart: () => {
@ -63,9 +63,9 @@ const useSimpleButton = (mgba: MgbaHandle, button: GbaKey) => {
},
};
}, [button, mgba]);
};
}
const relativeTouch = (touch: Touch) => {
function relativeTouch(touch: Touch) {
const target = (touch.target as Element).getBoundingClientRect();
const touchPoint = { x: touch.clientX, y: touch.clientY };
@ -82,15 +82,15 @@ const relativeTouch = (touch: Touch) => {
};
return relativePosition;
};
}
const useDpadTouch = (mgba: MgbaHandle) => {
function useDpadTouch(mgba: MgbaHandle) {
const [previouslyPressedButtons, setTouchedButtons] = useState<Set<GbaKey>>(
new Set()
);
return useMemo(() => {
const updateDpad = (touches: TouchList) => {
function updateDpad(touches: TouchList) {
const currentlyPressed = new Set<GbaKey>();
for (let touch of touches) {
@ -130,7 +130,7 @@ const useDpadTouch = (mgba: MgbaHandle) => {
}
setTouchedButtons(currentlyPressed);
};
}
return {
onTouchStart: (event: React.TouchEvent) =>
@ -141,15 +141,15 @@ const useDpadTouch = (mgba: MgbaHandle) => {
updateDpad(event.nativeEvent.targetTouches),
};
}, [mgba, previouslyPressedButtons]);
};
}
const useAbTouch = (mgba: MgbaHandle) => {
function useAbTouch(mgba: MgbaHandle) {
const [previouslyPressedButtons, setTouchedButtons] = useState<Set<GbaKey>>(
new Set()
);
return useMemo(() => {
const updateAbButtons = (touches: TouchList) => {
function updateAbButtons(touches: TouchList) {
const currentlyPressed = new Set<GbaKey>();
for (let touch of touches) {
@ -173,7 +173,7 @@ const useAbTouch = (mgba: MgbaHandle) => {
}
setTouchedButtons(currentlyPressed);
};
}
return {
onTouchStart: (event: React.TouchEvent) =>
@ -184,9 +184,9 @@ const useAbTouch = (mgba: MgbaHandle) => {
updateAbButtons(event.nativeEvent.targetTouches),
};
}, [mgba, previouslyPressedButtons]);
};
}
export const MobileController: FC<{ mgba: MgbaHandle }> = ({ mgba }) => {
export function MobileController({ mgba }: { mgba: MgbaHandle }) {
return (
<MobileControls onContextMenu={(evt) => evt.preventDefault()}>
<MobileControlsRow $size={MobileControlsSize.Small}>
@ -226,4 +226,4 @@ export const MobileController: FC<{ mgba: MgbaHandle }> = ({ mgba }) => {
</MobileControlsRow>
</MobileControls>
);
};
}

View file

@ -69,14 +69,16 @@ const ShowOnWideScreen = styled.div`
}
`;
const isTouchScreen = () => navigator.maxTouchPoints > 1;
function isTouchScreen() {
return navigator.maxTouchPoints > 1;
}
function shouldStartPlaying(isTouchScreen: boolean | undefined) {
if (isTouchScreen === undefined) return false;
return !isTouchScreen;
}
const MgbaWithControllerSides = () => {
function MgbaWithControllerSides() {
const mgba = useRef<MgbaHandle>(null);
const mgbaHandle = useMemo(
@ -128,7 +130,7 @@ const MgbaWithControllerSides = () => {
</ShowOnWideScreen>
</>
);
};
}
export default function Home() {
return (
<>

View file

@ -1,6 +1,6 @@
import { useEffect, useState } from "react";
export const useClientValue = <T,>(fn: () => T) => {
export function useClientValue<T>(fn: () => T) {
const [value, setValue] = useState<T>();
useEffect(() => {
setValue(fn());