UNPKG

use-smooth-scroll

Version:

React hook which gives a smooth scrolling function.

71 lines (65 loc) 2.52 kB
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;