feat(canvas): accelerate local previews and harden edge flows

This commit is contained in:
2026-04-05 17:28:43 +02:00
parent 451ab0b986
commit de37b63b2b
29 changed files with 2751 additions and 358 deletions

View File

@@ -1,5 +1,10 @@
import { useRef, useCallback, useEffect } from "react";
type DebouncedCallback<Args extends unknown[]> = ((...args: Args) => void) & {
flush: () => void;
cancel: () => void;
};
/**
* Debounced callback — ruft `callback` erst auf, wenn `delay` ms
* ohne erneuten Aufruf vergangen sind. Perfekt für Auto-Save.
@@ -7,9 +12,10 @@ import { useRef, useCallback, useEffect } from "react";
export function useDebouncedCallback<Args extends unknown[]>(
callback: (...args: Args) => void,
delay: number,
): (...args: Args) => void {
): DebouncedCallback<Args> {
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const callbackRef = useRef(callback);
const argsRef = useRef<Args | null>(null);
// Callback-Ref aktuell halten ohne neu zu rendern
useEffect(() => {
@@ -23,15 +29,49 @@ export function useDebouncedCallback<Args extends unknown[]>(
};
}, []);
const cancel = useCallback(() => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
timeoutRef.current = null;
}
argsRef.current = null;
}, []);
const flush = useCallback(() => {
if (!timeoutRef.current) {
return;
}
clearTimeout(timeoutRef.current);
timeoutRef.current = null;
const args = argsRef.current;
argsRef.current = null;
if (args) {
callbackRef.current(...args);
}
}, []);
const debouncedFn = useCallback(
(...args: Args) => {
argsRef.current = args;
if (timeoutRef.current) clearTimeout(timeoutRef.current);
timeoutRef.current = setTimeout(() => {
callbackRef.current(...args);
timeoutRef.current = null;
const nextArgs = argsRef.current;
argsRef.current = null;
if (nextArgs) {
callbackRef.current(...nextArgs);
}
}, delay);
},
[delay],
);
return debouncedFn;
const debouncedCallback = debouncedFn as DebouncedCallback<Args>;
debouncedCallback.flush = flush;
debouncedCallback.cancel = cancel;
return debouncedCallback;
}