use-smooth-scroll
Version:
React hook which gives a smooth scrolling function.
71 lines (65 loc) • 2.52 kB
JavaScript
import { easeOut } from '@popmotion/easing';
import { mix } from '@popmotion/popcorn';
import arePassiveEventsSupported from 'are-passive-events-supported';
import durationProgress from 'callbag-duration-progress';
import flatten from 'callbag-flatten';
import fromEvent from 'callbag-from-event';
import map from 'callbag-map';
import merge from 'callbag-merge';
import of from 'callbag-of';
import subject from 'callbag-subject';
import subscribe from 'callbag-subscribe';
import takeUntil from 'callbag-take-until';
import { useRef, useEffect, useCallback } from 'react';
import useConstant from 'use-constant';
var ONCE = [];
var PASSIVE =
/*#__PURE__*/
arePassiveEventsSupported() ? {
passive: true
} : undefined;
function useSmoothScroll(axis, ref) {
var command$ = useConstant(subject);
var argumentsRef = useRef();
useEffect(function () {
argumentsRef.current = [axis === 'x' ? 'scrollLeft' : 'scrollTop', ref.current];
});
var scrollTo = useCallback(function (target, _temp) {
var _ref = _temp === void 0 ? {} : _temp,
_ref$duration = _ref.duration,
duration = _ref$duration === void 0 ? 300 : _ref$duration,
_ref$easing = _ref.easing,
easing = _ref$easing === void 0 ? easeOut : _ref$easing;
var _argumentsRef$current = argumentsRef.current,
scrollProperty = _argumentsRef$current[0],
node = _argumentsRef$current[1];
command$(1, [scrollProperty, node, target, duration, easing]);
}, ONCE);
useEffect(function () {
return subscribe(function (_ref2) {
var node = _ref2[0],
scrollProperty = _ref2[1],
v = _ref2[2];
node[scrollProperty] = v;
})(flatten(map(function (_ref3) {
var scrollProperty = _ref3[0],
node = _ref3[1],
target = _ref3[2],
duration = _ref3[3],
easing = _ref3[4];
var recyclable = [node, scrollProperty, 0];
var start = node[scrollProperty];
var resolvedDuration = Math.max(0, typeof duration === 'function' ? duration(Math.abs(target - start)) : duration);
if (resolvedDuration === 0) {
recyclable[2] = target;
return of(recyclable);
}
return takeUntil(merge(fromEvent(node, 'wheel', PASSIVE), fromEvent(node, 'touchstart', PASSIVE)))(map(function (p) {
recyclable[2] = mix(start, target, easing(p));
return recyclable;
})(durationProgress(resolvedDuration)));
})(command$)));
}, ONCE);
return scrollTo;
}
export default useSmoothScroll;