fix: improve animation hook robustness

- Add .catch handler to scheduleNext to prevent unhandled promise
  rejections from killing the scheduling loop
- Replace `as unknown as Animation` cast with Cancellable interface
  for type-safe cleanup handles
This commit is contained in:
Jannis Braun
2026-03-22 23:31:50 +01:00
parent 977983eed1
commit 43eaceadc0
+8 -4
View File
@@ -13,8 +13,9 @@ export function useMascotAnimation(
containerRef: React.RefObject<HTMLDivElement | null>, containerRef: React.RefObject<HTMLDivElement | null>,
state: MascotState, state: MascotState,
): void { ): void {
interface Cancellable { cancel(): void }
const timeoutRef = useRef<number | null>(null); const timeoutRef = useRef<number | null>(null);
const activeAnimations = useRef<Animation[]>([]); const activeAnimations = useRef<Cancellable[]>([]);
const abortedRef = useRef(false); const abortedRef = useRef(false);
useEffect(() => { useEffect(() => {
@@ -93,6 +94,11 @@ export function useMascotAnimation(
if (!abortedRef.current) { if (!abortedRef.current) {
scheduleNext(fn, minMs, maxMs); scheduleNext(fn, minMs, maxMs);
} }
}).catch(() => {
// Action failed — reschedule unless aborted
if (!abortedRef.current) {
scheduleNext(fn, minMs, maxMs);
}
}); });
}, delay); }, delay);
} }
@@ -469,9 +475,7 @@ export function useMascotAnimation(
// Store initial timeout so cleanup can cancel it // Store initial timeout so cleanup can cancel it
activeAnimations.current.push({ activeAnimations.current.push({
cancel: () => clearTimeout(initialTimeout), cancel: () => clearTimeout(initialTimeout),
finished: Promise.resolve(), });
playState: 'running',
} as unknown as Animation);
} }
// ═══ LONELY STATE ═══ // ═══ LONELY STATE ═══