TelegramPWA/src/hooks/useHeavyAnimation.ts

73 lines
1.8 KiB
TypeScript

import {
getIsHeavyAnimating,
useCallback, useEffect, useMemo, useRef,
} from '../lib/teact/teact';
import { createCallbackManager } from '../util/callbacks';
import useLastCallback from './useLastCallback';
export const startCallbacks = createCallbackManager();
export const endCallbacks = createCallbackManager();
getIsHeavyAnimating.subscribe(() => {
if (getIsHeavyAnimating()) {
startCallbacks.runCallbacks();
} else {
endCallbacks.runCallbacks();
}
});
export default function useHeavyAnimation(
onStart?: AnyToVoidFunction,
onEnd?: AnyToVoidFunction,
isDisabled = false,
) {
const lastOnStart = useLastCallback(onStart);
const lastOnEnd = useLastCallback(onEnd);
useEffect(() => {
if (isDisabled) {
return undefined;
}
if (getIsHeavyAnimating()) {
lastOnStart();
}
startCallbacks.addCallback(lastOnStart);
endCallbacks.addCallback(lastOnEnd);
return () => {
endCallbacks.removeCallback(lastOnEnd);
startCallbacks.removeCallback(lastOnStart);
};
}, [isDisabled, lastOnEnd, lastOnStart]);
}
// TODO → `onFullyIdle`?
export function useThrottleForHeavyAnimation<T extends AnyToVoidFunction>(afterHeavyAnimation: T, deps: unknown[]) {
// eslint-disable-next-line react-hooks-static-deps/exhaustive-deps
const fnMemo = useCallback(afterHeavyAnimation, deps);
const isScheduledRef = useRef(false);
return useMemo(() => {
return (...args: Parameters<T>) => {
if (!isScheduledRef.current) {
if (!getIsHeavyAnimating()) {
fnMemo(...args);
return;
}
isScheduledRef.current = true;
const removeCallback = endCallbacks.addCallback(() => {
fnMemo(...args);
removeCallback();
isScheduledRef.current = false;
});
}
};
}, [fnMemo]);
}