UNPKG

@tanem/react-nprogress

Version:

A React primitive for building slim progress bars.

298 lines (285 loc) 11.8 kB
'use strict'; var _objectWithoutProperties = require('@babel/runtime/helpers/objectWithoutProperties'); var _defineProperty = require('@babel/runtime/helpers/defineProperty'); var _slicedToArray = require('@babel/runtime/helpers/slicedToArray'); var react = require('react'); var jsxRuntime = require('react/jsx-runtime'); var hoistNonReactStatics = require('hoist-non-react-statics'); var clamp = function clamp(num, lower, upper) { num = num <= upper ? num : upper; num = num >= lower ? num : lower; return num; }; var createQueue = function createQueue() { var isRunning = false; var pending = []; var _next = function next() { isRunning = true; var cb = pending.shift(); if (cb) { return cb(_next); } isRunning = false; }; var clear = function clear() { isRunning = false; pending = []; }; var enqueue = function enqueue(cb) { pending.push(cb); if (!isRunning && pending.length === 1) { _next(); } }; return { clear: clear, enqueue: enqueue }; }; // Uses requestAnimationFrame rather than setTimeout for smoother animation // timing. Note that rAF is throttled or paused in background tabs, so progress // will stall when the tab is hidden and resume when it regains focus. var createTimeout = function createTimeout() { var handle; var cancel = function cancel() { if (handle !== undefined) { window.cancelAnimationFrame(handle); } }; var schedule = function schedule(callback, delay) { cancel(); var deltaTime; var start; var _frame = function frame(time) { start = start || time; deltaTime = time - start; if (deltaTime > delay) { callback(); return; } handle = window.requestAnimationFrame(_frame); }; handle = window.requestAnimationFrame(_frame); }; return { cancel: cancel, schedule: schedule }; }; var increment = function increment(progress) { var amount = 0; if (progress >= 0 && progress < 0.2) { amount = 0.1; } else if (progress >= 0.2 && progress < 0.5) { amount = 0.04; } else if (progress >= 0.5 && progress < 0.8) { amount = 0.02; } else if (progress >= 0.8 && progress < 0.99) { amount = 0.005; } return clamp(progress + amount, 0, 0.994); }; // Hat-tip: // https://github.com/streamich/react-use/blob/master/src/useEffectOnce.ts. // // `react-use` appears to be unmaintained, so moving the required code into // this project for now. var useEffectOnce = function useEffectOnce(effect) { // eslint-disable-next-line react-hooks/exhaustive-deps react.useEffect(effect, []); }; function ownKeys$2(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread$2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$2(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$2(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } var incrementParameter = function incrementParameter(num) { return ++num % 1000000; }; var useUpdate = function useUpdate() { var _useState = react.useState(0), _useState2 = _slicedToArray(_useState, 2), setState = _useState2[1]; return react.useCallback(function () { return setState(incrementParameter); }, []); }; var useGetSetState = function useGetSetState() { var initialState = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var update = useUpdate(); var state = react.useRef(_objectSpread$2({}, initialState)); var get = react.useCallback(function () { return state.current; }, []); var set = react.useCallback(function (patch) { if (!patch) { return; } Object.assign(state.current, patch); update(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return [get, set]; }; // Hat-tip: // https://github.com/streamich/react-use/blob/master/src/useUpdateEffect.ts. // // `react-use` appears to be unmaintained, so moving the required code into // this project for now. var useFirstMountState = function useFirstMountState() { var isFirst = react.useRef(true); if (isFirst.current) { isFirst.current = false; return true; } return isFirst.current; }; var useUpdateEffect = function useUpdateEffect(effect, deps) { var isFirstMount = useFirstMountState(); react.useEffect(function () { if (!isFirstMount) { return effect(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, deps); }; function ownKeys$1(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread$1(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$1(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$1(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } /* istanbul ignore next */ var noop = function noop() { return undefined; }; // State includes a `sideEffect` callback that bridges imperative queue // operations into React's declarative model. Each `setState` stores a callback; // `useUpdateEffect` fires it after React commits the update. This lets the // queue drive animations and schedule follow-up work without breaking React's // rendering lifecycle. var initialState = { isFinished: true, progress: 0, sideEffect: noop }; var useNProgress = function useNProgress() { var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, _ref$animationDuratio = _ref.animationDuration, animationDuration = _ref$animationDuratio === void 0 ? 200 : _ref$animationDuratio, _ref$incrementDuratio = _ref.incrementDuration, incrementDuration = _ref$incrementDuratio === void 0 ? 200 : _ref$incrementDuratio, _ref$isAnimating = _ref.isAnimating, isAnimating = _ref$isAnimating === void 0 ? false : _ref$isAnimating, _ref$minimum = _ref.minimum, minimum = _ref$minimum === void 0 ? 0.08 : _ref$minimum; var _useGetSetState = useGetSetState(initialState), _useGetSetState2 = _slicedToArray(_useGetSetState, 2), get = _useGetSetState2[0], setState = _useGetSetState2[1]; var queue = react.useRef(null); var timeout = react.useRef(null); useEffectOnce(function () { queue.current = createQueue(); timeout.current = createTimeout(); }); var cleanup = react.useCallback(function () { var _timeout$current, _queue$current; (_timeout$current = timeout.current) === null || _timeout$current === void 0 || _timeout$current.cancel(); (_queue$current = queue.current) === null || _queue$current === void 0 || _queue$current.clear(); }, []); var set = react.useCallback(function (n) { var _queue$current4; n = clamp(n, minimum, 1); // Unlike the original nprogress `done()`, completion does not include a // random progress jump before animating to 1. This keeps the primitive // predictable; consumers can set a higher progress value before stopping // the animation if they want that effect. if (n === 1) { var _queue$current2, _queue$current3; cleanup(); (_queue$current2 = queue.current) === null || _queue$current2 === void 0 || _queue$current2.enqueue(function (next) { setState({ progress: n, sideEffect: function sideEffect() { var _timeout$current2; return (_timeout$current2 = timeout.current) === null || _timeout$current2 === void 0 ? void 0 : _timeout$current2.schedule(next, animationDuration); } }); }); (_queue$current3 = queue.current) === null || _queue$current3 === void 0 || _queue$current3.enqueue(function () { setState({ isFinished: true, sideEffect: cleanup }); }); return; } (_queue$current4 = queue.current) === null || _queue$current4 === void 0 || _queue$current4.enqueue(function (next) { setState({ isFinished: false, progress: n, sideEffect: next }); }); }, [animationDuration, cleanup, minimum, queue, setState, timeout]); var trickle = react.useCallback(function () { set(increment(get().progress)); }, [get, set]); var start = react.useCallback(function () { // The original nprogress calls set(0) - which clamps to `minimum` - before // the first trickle. Here, the first trickle starts from increment(0) = // 0.1, so the bar appears at max(0.1, minimum) rather than exactly // `minimum`. The difference is negligible at the default minimum of 0.08. var _work = function work() { var _queue$current5; trickle(); (_queue$current5 = queue.current) === null || _queue$current5 === void 0 || _queue$current5.enqueue(function (next) { var _timeout$current3; (_timeout$current3 = timeout.current) === null || _timeout$current3 === void 0 || _timeout$current3.schedule(function () { _work(); next(); }, incrementDuration); }); }; _work(); }, [incrementDuration, queue, timeout, trickle]); var sideEffect = get().sideEffect; useEffectOnce(function () { if (isAnimating) { start(); } return cleanup; }); useUpdateEffect(function () { get().sideEffect(); }, [get, sideEffect]); useUpdateEffect(function () { if (!isAnimating) { set(1); } else { setState(_objectSpread$1(_objectSpread$1({}, initialState), {}, { sideEffect: start })); } }, [isAnimating, set, setState, start]); return { animationDuration: animationDuration, isFinished: get().isFinished, progress: get().progress }; }; var _excluded = ["children"]; var NProgress = function NProgress(_ref) { var children = _ref.children, restProps = _objectWithoutProperties(_ref, _excluded); var renderProps = useNProgress(restProps); return children(renderProps); }; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function withNProgress(BaseComponent) { var WithNProgress = function WithNProgress(props) { var hookProps = useNProgress(props); return jsxRuntime.jsx(BaseComponent, _objectSpread(_objectSpread({}, props), hookProps)); }; hoistNonReactStatics(WithNProgress, BaseComponent); return WithNProgress; } exports.NProgress = NProgress; exports.useNProgress = useNProgress; exports.withNProgress = withNProgress; //# sourceMappingURL=react-nprogress.cjs.development.js.map