@anton.bobrov/react-vevet-hooks
Version:
A collection of custom React hooks designed to seamlessly integrate with the `Vevet` library
84 lines (83 loc) • 3.3 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);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.useAnimationFrameSync = void 0;
var react_hooks_1 = require("@anton.bobrov/react-hooks");
var react_1 = require("react");
var vevet_1 = require("vevet");
var useAnimationFrame_1 = require("./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
*/
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 = (0, react_hooks_1.useEvent)(onUpdateProp);
var onSet = (0, react_hooks_1.useEvent)(onSetProp);
var dataRef = (0, react_1.useRef)({
moment: __assign({}, initialData),
target: __assign({}, initialData),
});
var props = (0, react_hooks_1.objectKeys)(initialData);
var _c = dataRef.current, moment = _c.moment, target = _c.target;
var render = (0, react_hooks_1.useEvent)(function (ease) {
props.forEach(function (prop) {
// @ts-ignore
moment[prop] = (0, vevet_1.lerp)(moment[prop], target[prop], ease);
});
onUpdate(moment);
});
var _d = (0, useAnimationFrame_1.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 = (0, react_1.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 = (0, react_1.useCallback)(function () { return moment; }, [moment]);
return { set: set, getMoment: getMoment };
}
exports.useAnimationFrameSync = useAnimationFrameSync;