tick button can be held for ticks
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import type Decimal from 'break_eternity.js';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import type { PointerEvent } from 'react';
|
||||
|
||||
interface Props {
|
||||
time: Decimal;
|
||||
@@ -7,7 +9,47 @@ interface Props {
|
||||
onInitialize: () => void;
|
||||
}
|
||||
|
||||
const HOLD_TICK_INTERVAL_MS = 1000;
|
||||
const MIN_TICK_INTERVAL_MS = 50;
|
||||
|
||||
export default function Topbar({ time, onTick, onReset, onInitialize }: Props) {
|
||||
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
// Mutable, not React state: doTick reschedules itself via setTimeout, so it must always read
|
||||
// and write the CURRENT speed directly — a value captured in a render's closure (e.g. via
|
||||
// useState) would stay frozen for the lifetime of that closure, since nothing ever forces
|
||||
// doTick to be re-created from a fresh render while a hold is in progress.
|
||||
const speedRef = useRef(HOLD_TICK_INTERVAL_MS);
|
||||
|
||||
function stopHolding() {
|
||||
if (timeoutRef.current !== null) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
timeoutRef.current = null;
|
||||
}
|
||||
speedRef.current = HOLD_TICK_INTERVAL_MS;
|
||||
}
|
||||
|
||||
function doTick() {
|
||||
onTick();
|
||||
speedRef.current = Math.max(MIN_TICK_INTERVAL_MS, Math.pow(speedRef.current, 0.97));
|
||||
timeoutRef.current = setTimeout(doTick, speedRef.current);
|
||||
}
|
||||
|
||||
function startHolding(e: PointerEvent<HTMLButtonElement>) {
|
||||
if (e.button !== 0)
|
||||
return;
|
||||
e.currentTarget.setPointerCapture(e.pointerId);
|
||||
stopHolding();
|
||||
doTick();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('blur', stopHolding);
|
||||
return () => {
|
||||
window.removeEventListener('blur', stopHolding);
|
||||
stopHolding();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="topbar">
|
||||
<h1 className="topbar__title">
|
||||
@@ -24,7 +66,12 @@ export default function Topbar({ time, onTick, onReset, onInitialize }: Props) {
|
||||
<button className="btn" onClick={onReset}>
|
||||
Reset
|
||||
</button>
|
||||
<button className="btn btn--primary" onClick={onTick}>
|
||||
<button
|
||||
className="btn btn--primary"
|
||||
onPointerDown={startHolding}
|
||||
onPointerUp={stopHolding}
|
||||
onPointerCancel={stopHolding}
|
||||
>
|
||||
Tick ▶
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user