import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties';
import _defineProperty from '@babel/runtime/helpers/defineProperty';
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
import { useEffect, useRef, useCallback, useState } from 'react';
import { jsx } from 'react/jsx-runtime';
import hoistNonReactStatics from '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
  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 = useState(0),
    _useState2 = _slicedToArray(_useState, 2),
    setState = _useState2[1];
  return useCallback(function () {
    return setState(incrementParameter);
  }, []);
};
var useGetSetState = function useGetSetState() {
  var initialState = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  var update = useUpdate();
  var state = useRef(_objectSpread$2({}, initialState));
  var get = useCallback(function () {
    return state.current;
  }, []);
  var set = 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 = useRef(true);
  if (isFirst.current) {
    isFirst.current = false;
    return true;
  }
  return isFirst.current;
};
var useUpdateEffect = function useUpdateEffect(effect, deps) {
  var isFirstMount = useFirstMountState();
  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 = useRef(null);
  var timeout = useRef(null);
  useEffectOnce(function () {
    queue.current = createQueue();
    timeout.current = createTimeout();
  });
  var cleanup = 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 = 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 = useCallback(function () {
    set(increment(get().progress));
  }, [get, set]);
  var start = 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 jsx(BaseComponent, _objectSpread(_objectSpread({}, props), hookProps));
  };
  hoistNonReactStatics(WithNProgress, BaseComponent);
  return WithNProgress;
}

export { NProgress, useNProgress, withNProgress };
//# sourceMappingURL=react-nprogress.esm.js.map
