1a9f0f2557
Co-authored-by: Cursor <cursoragent@cursor.com>
96 lines
2.7 KiB
TypeScript
96 lines
2.7 KiB
TypeScript
import { useCallback, useEffect, useRef } from 'react';
|
|
|
|
/** Во время drag шлёт onMove не чаще одного раза за кадр (для live-синхронизации презентации). */
|
|
export function useLiveDragBroadcast(
|
|
onMove: ((id: string, nx: number, ny: number) => void) | undefined,
|
|
id: string,
|
|
): {
|
|
schedule: (nx: number, ny: number) => void;
|
|
flush: (nx: number, ny: number) => void;
|
|
} {
|
|
const rafRef = useRef(0);
|
|
const pendingRef = useRef<{ nx: number; ny: number } | null>(null);
|
|
const onMoveRef = useRef(onMove);
|
|
onMoveRef.current = onMove;
|
|
const idRef = useRef(id);
|
|
idRef.current = id;
|
|
|
|
useEffect(
|
|
() => () => {
|
|
if (rafRef.current) cancelAnimationFrame(rafRef.current);
|
|
},
|
|
[],
|
|
);
|
|
|
|
const schedule = useCallback((nx: number, ny: number) => {
|
|
if (!onMoveRef.current) return;
|
|
pendingRef.current = { nx, ny };
|
|
if (rafRef.current) return;
|
|
rafRef.current = requestAnimationFrame(() => {
|
|
rafRef.current = 0;
|
|
const pending = pendingRef.current;
|
|
const cb = onMoveRef.current;
|
|
if (!pending || !cb) return;
|
|
cb(idRef.current, pending.nx, pending.ny);
|
|
});
|
|
}, []);
|
|
|
|
const flush = useCallback((nx: number, ny: number) => {
|
|
if (rafRef.current) {
|
|
cancelAnimationFrame(rafRef.current);
|
|
rafRef.current = 0;
|
|
}
|
|
pendingRef.current = null;
|
|
onMoveRef.current?.(idRef.current, nx, ny);
|
|
}, []);
|
|
|
|
return { schedule, flush };
|
|
}
|
|
|
|
/** Во время resize шлёт onResize не чаще одного раза за кадр. */
|
|
export function useLiveResizeBroadcast(
|
|
onResize: ((id: string, sizeN: number) => void) | undefined,
|
|
id: string,
|
|
): {
|
|
schedule: (sizeN: number) => void;
|
|
flush: (sizeN: number) => void;
|
|
} {
|
|
const rafRef = useRef(0);
|
|
const pendingRef = useRef<number | null>(null);
|
|
const onResizeRef = useRef(onResize);
|
|
onResizeRef.current = onResize;
|
|
const idRef = useRef(id);
|
|
idRef.current = id;
|
|
|
|
useEffect(
|
|
() => () => {
|
|
if (rafRef.current) cancelAnimationFrame(rafRef.current);
|
|
},
|
|
[],
|
|
);
|
|
|
|
const schedule = useCallback((sizeN: number) => {
|
|
if (!onResizeRef.current) return;
|
|
pendingRef.current = sizeN;
|
|
if (rafRef.current) return;
|
|
rafRef.current = requestAnimationFrame(() => {
|
|
rafRef.current = 0;
|
|
const pending = pendingRef.current;
|
|
const cb = onResizeRef.current;
|
|
if (pending === null || !cb) return;
|
|
cb(idRef.current, pending);
|
|
});
|
|
}, []);
|
|
|
|
const flush = useCallback((sizeN: number) => {
|
|
if (rafRef.current) {
|
|
cancelAnimationFrame(rafRef.current);
|
|
rafRef.current = 0;
|
|
}
|
|
pendingRef.current = null;
|
|
onResizeRef.current?.(idRef.current, sizeN);
|
|
}, []);
|
|
|
|
return { schedule, flush };
|
|
}
|