@tanem/react-nprogress
Version:
A React primitive for building slim progress bars.
298 lines (285 loc) • 11.8 kB
JavaScript
;
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