@anton.bobrov/react-vevet-hooks
Version:
A collection of custom React hooks designed to seamlessly integrate with the `Vevet` library
80 lines • 3.04 kB
JavaScript
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
import { objectKeys, useEvent } from '@anton.bobrov/react-hooks';
import { useCallback, useRef } from 'react';
import { lerp } from 'vevet';
import { useAnimationFrame } from './useAnimationFrame';
/**
* Custom React hook that synchronizes animation frame data using linear interpolation.
*
* This hook allows you to smoothly animate properties by specifying their initial values.
* It uses linear interpolation to transition between current and target values.
* The animation frame will automatically stop once all values reach their targets.
*
* @example
* const { set } = useAnimationFrameSync({
* data: { x: 0, y: 0 },
* onUpdate: ({ x, y }) => console.log(x, y),
* });
*
* set('x', 1);
* set('y', 0.5);
* set('y', 0.5, true); // instant change
*/
export function useAnimationFrameSync(_a) {
var initialData = _a.data, onUpdateProp = _a.onUpdate, onSetProp = _a.onSet, _b = _a.ease, easeProp = _b === void 0 ? 0.1 : _b;
var onUpdate = useEvent(onUpdateProp);
var onSet = useEvent(onSetProp);
var dataRef = useRef({
moment: __assign({}, initialData),
target: __assign({}, initialData),
});
var props = objectKeys(initialData);
var _c = dataRef.current, moment = _c.moment, target = _c.target;
var render = useEvent(function (ease) {
props.forEach(function (prop) {
// @ts-ignore
moment[prop] = lerp(moment[prop], target[prop], ease);
});
onUpdate(moment);
});
var _d = useAnimationFrame({
onFrame: function (_a) {
var fpsMultiplier = _a.fpsMultiplier;
var ease = easeProp * fpsMultiplier;
render(ease);
var undone = props.filter(function (prop) { return moment[prop] !== target[prop]; });
var isInterpolated = undone.length === 0;
if (isInterpolated) {
pause();
}
},
}), play = _d.play, pause = _d.pause;
var set = useCallback(function (prop, value, isInstant) {
// @ts-ignore
target[prop] = value;
// instant change
if (isInstant) {
// @ts-ignore
moment[prop] = value;
render(0);
}
else {
// interpolated change
play();
}
onSet === null || onSet === void 0 ? void 0 : onSet(target);
}, [moment, onSet, play, render, target]);
var getMoment = useCallback(function () { return moment; }, [moment]);
return { set: set, getMoment: getMoment };
}
//# sourceMappingURL=useAnimationFrameSync.js.map