'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var utils = require('@motionone/utils'); var velocity = require('../utils/velocity.cjs.js'); var index = require('../spring/index.cjs.js'); const glide = ({ from = 0, velocity: velocity$1 = 0.0, power = 0.8, decay = 0.325, bounceDamping, bounceStiffness, changeTarget, min, max, restDistance = 0.5, restSpeed, }) => { decay = utils.time.ms(decay); const state = { hasReachedTarget: false, done: false, current: from, target: from, }; const isOutOfBounds = (v) => (min !== undefined && v < min) || (max !== undefined && v > max); const nearestBoundary = (v) => { if (min === undefined) return max; if (max === undefined) return min; return Math.abs(min - v) < Math.abs(max - v) ? min : max; }; let amplitude = power * velocity$1; const ideal = from + amplitude; const target = changeTarget === undefined ? ideal : changeTarget(ideal); state.target = target; /** * If the target has changed we need to re-calculate the amplitude, otherwise * the animation will start from the wrong position. */ if (target !== ideal) amplitude = target - from; const calcDelta = (t) => -amplitude * Math.exp(-t / decay); const calcLatest = (t) => target + calcDelta(t); const applyFriction = (t) => { const delta = calcDelta(t); const latest = calcLatest(t); state.done = Math.abs(delta) <= restDistance; state.current = state.done ? target : latest; }; /** * Ideally this would resolve for t in a stateless way, we could * do that by always precalculating the animation but as we know * this will be done anyway we can assume that spring will * be discovered during that. */ let timeReachedBoundary; let spring; const checkCatchBoundary = (t) => { if (!isOutOfBounds(state.current)) return; timeReachedBoundary = t; spring = index.spring({ from: state.current, to: nearestBoundary(state.current), velocity: velocity.calcGeneratorVelocity(calcLatest, t, state.current), damping: bounceDamping, stiffness: bounceStiffness, restDistance, restSpeed, }); }; checkCatchBoundary(0); return (t) => { /** * We need to resolve the friction to figure out if we need a * spring but we don't want to do this twice per frame. So here * we flag if we updated for this frame and later if we did * we can skip doing it again. */ let hasUpdatedFrame = false; if (!spring && timeReachedBoundary === undefined) { hasUpdatedFrame = true; applyFriction(t); checkCatchBoundary(t); } /** * If we have a spring and the provided t is beyond the moment the friction * animation crossed the min/max boundary, use the spring. */ if (timeReachedBoundary !== undefined && t > timeReachedBoundary) { state.hasReachedTarget = true; return spring(t - timeReachedBoundary); } else { state.hasReachedTarget = false; !hasUpdatedFrame && applyFriction(t); return state; } }; }; exports.glide = glide;