Files
element-web/src/hooks/useSmoothAnimation.ts
David Langley 69ee8fd96a Change License: AGPL + Element Commercial (#28856)
* Add commercial licence and update config files

* Update license in headers

* Revert "Update license in headers"

This reverts commit 7ed7949485.

* Update only spdx id

* Remove LicenseRef- from package.json

LicenseRef- no longer allowed in npm v3 package.json
This fixes the warning in the logs and failing build check.
2025-01-06 11:18:54 +00:00

72 lines
2.7 KiB
TypeScript

/*
Copyright 2024 New Vector Ltd.
Copyright 2022 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { logger } from "matrix-js-sdk/src/logger";
import { useCallback, useEffect, useRef, useState } from "react";
import SettingsStore from "../settings/SettingsStore";
import { useAnimation } from "./useAnimation";
const debuglog = (...args: any[]): void => {
if (SettingsStore.getValue("debug_animation")) {
logger.log.call(console, "Animation debuglog:", ...args);
}
};
/**
* Utility function to smoothly animate to a certain target value
* @param initialValue Initial value to be used as initial starting point
* @param targetValue Desired value to animate to (can be changed repeatedly to whatever is current at that time)
* @param duration Duration that each animation should take, specify 0 to skip animating
*/
export function useSmoothAnimation(initialValue: number, targetValue: number, duration: number): number {
const state = useRef<{ timestamp: DOMHighResTimeStamp | null; value: number }>({
timestamp: null,
value: initialValue,
});
const [currentValue, setCurrentValue] = useState<number>(initialValue);
const [currentStepSize, setCurrentStepSize] = useState<number>(0);
useEffect(() => {
const totalDelta = targetValue - state.current.value;
setCurrentStepSize(totalDelta / duration);
state.current = { ...state.current, timestamp: null };
}, [duration, targetValue]);
const update = useCallback(
(timestamp: DOMHighResTimeStamp): boolean => {
if (!state.current.timestamp) {
state.current = { ...state.current, timestamp };
return true;
}
if (Math.abs(currentStepSize) < Number.EPSILON) {
return false;
}
const timeDelta = timestamp - state.current.timestamp;
const valueDelta = currentStepSize * timeDelta;
const maxValueDelta = targetValue - state.current.value;
const clampedValueDelta = Math.sign(valueDelta) * Math.min(Math.abs(maxValueDelta), Math.abs(valueDelta));
const value = state.current.value + clampedValueDelta;
debuglog(`Animating to ${targetValue} at ${value} timeDelta=${timeDelta}, valueDelta=${valueDelta}`);
setCurrentValue(value);
state.current = { value, timestamp };
return Math.abs(maxValueDelta) > Number.EPSILON;
},
[currentStepSize, targetValue],
);
useAnimation(duration > 0, update);
return duration > 0 ? currentValue : targetValue;
}