@tanem/react-nprogress 6.0.4 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +114 -108
  2. package/dist/react-nprogress.cjs +124 -0
  3. package/dist/react-nprogress.cjs.map +1 -0
  4. package/dist/react-nprogress.d.cts +26 -0
  5. package/dist/react-nprogress.d.cts.map +1 -0
  6. package/dist/react-nprogress.d.mts +26 -0
  7. package/dist/react-nprogress.d.mts.map +1 -0
  8. package/dist/react-nprogress.mjs +122 -0
  9. package/dist/react-nprogress.mjs.map +1 -0
  10. package/package.json +50 -36
  11. package/src/NProgress.tsx +13 -0
  12. package/src/clamp.ts +5 -0
  13. package/src/createTimeout.ts +35 -0
  14. package/src/env.d.ts +0 -0
  15. package/src/increment.ts +17 -0
  16. package/src/index.tsx +3 -0
  17. package/src/types.ts +13 -0
  18. package/src/useNProgress.tsx +137 -0
  19. package/dist/NProgress.d.ts +0 -8
  20. package/dist/clamp.d.ts +0 -1
  21. package/dist/createQueue.d.ts +0 -7
  22. package/dist/createTimeout.d.ts +0 -4
  23. package/dist/increment.d.ts +0 -1
  24. package/dist/index.d.ts +0 -3
  25. package/dist/index.js +0 -7
  26. package/dist/react-nprogress.cjs.development.js +0 -299
  27. package/dist/react-nprogress.cjs.development.js.map +0 -1
  28. package/dist/react-nprogress.cjs.production.js +0 -2
  29. package/dist/react-nprogress.cjs.production.js.map +0 -1
  30. package/dist/react-nprogress.esm.js +0 -295
  31. package/dist/react-nprogress.esm.js.map +0 -1
  32. package/dist/react-nprogress.umd.development.js +0 -727
  33. package/dist/react-nprogress.umd.development.js.map +0 -1
  34. package/dist/react-nprogress.umd.production.js +0 -2
  35. package/dist/react-nprogress.umd.production.js.map +0 -1
  36. package/dist/types.d.ts +0 -6
  37. package/dist/useEffectOnce.d.ts +0 -2
  38. package/dist/useGetSetState.d.ts +0 -1
  39. package/dist/useNProgress.d.ts +0 -6
  40. package/dist/useUpdateEffect.d.ts +0 -2
  41. package/dist/withNProgress.d.ts +0 -7
package/README.md CHANGED
@@ -8,22 +8,30 @@
8
8
 
9
9
  > A React primitive for building slim progress bars.
10
10
 
11
- [Background](#background) | [Usage](#usage) | [Live Examples](#live-examples) | [API](#api) | [Installation](#installation) | [License](#license)
11
+ [Background](#background) | [When to Use This](#when-to-use-this) | [Usage](#usage) | [API](#api) | [Live Examples](#live-examples) | [Installation](#installation) | [Contributing](#contributing) | [License](#license)
12
12
 
13
13
  ## Background
14
14
 
15
15
  This is a React port of [rstacruz](https://github.com/rstacruz)'s [`nprogress`](https://github.com/rstacruz/nprogress) module. It exposes an API that encapsulates the logic of `nprogress` and renders nothing, allowing consumers to implement their own rendering.
16
16
 
17
+ Two versions of `nprogress` are in circulation and they trickle differently. The 2014 npm release, `0.2.0`, adds a random amount of at most `0.02` every 800ms. The repository's master branch, never published to npm, adds tiered amounts every 200ms. This library mirrors master, so a side by side comparison against the npm package or the official demo page will show a different pace. The [`increment`](#increment) option covers the `0.2.0` pacing if you prefer the older feel.
18
+
19
+ ## When to Use This
20
+
21
+ This package is a headless primitive. It renders no markup and ships no CSS, supplying only the pacing state: a `progress` value that trickles towards completion, an `isFinished` flag, and the `animationDuration` to transition with. The bar itself is yours to write.
22
+
23
+ - Use a drop-in bar such as [`nextjs-toploader`](https://github.com/TheSGJ/nextjs-toploader), [`next-nprogress-bar`](https://github.com/Skyleen77/next-nprogress-bar), or [`nprogress`](https://github.com/rstacruz/nprogress) itself when you want a styled bar wired up to your router with no rendering work.
24
+ - Use this package when you render the bar yourself, for example with design-system components or custom containers and spinners, and want only the trickle and completion logic handled for you.
25
+ - Use this package when you need several progress bars on one page, each tracking its own state.
26
+
17
27
  ## Usage
18
28
 
19
- In the following examples, `Container`, `Bar` and `Spinner` are custom components.
29
+ `Container`, `Bar` and `Spinner` are components you write: this package renders nothing itself. Every entry in [Live Examples](#live-examples) contains a working implementation of all three.
20
30
 
21
31
  **Hook**
22
32
 
23
33
  ```jsx
24
34
  import { useNProgress } from '@tanem/react-nprogress'
25
- import React from 'react'
26
- import { render } from 'react-dom'
27
35
 
28
36
  import Bar from './Bar'
29
37
  import Container from './Container'
@@ -41,170 +49,168 @@ const Progress = ({ isAnimating }) => {
41
49
  </Container>
42
50
  )
43
51
  }
44
-
45
- render(<Progress isAnimating />, document.getElementById('root'))
46
52
  ```
47
53
 
48
54
  **Render Props**
49
55
 
50
56
  ```jsx
51
57
  import { NProgress } from '@tanem/react-nprogress'
52
- import React from 'react'
53
- import { render } from 'react-dom'
54
58
 
55
59
  import Bar from './Bar'
56
60
  import Container from './Container'
57
61
  import Spinner from './Spinner'
58
62
 
59
- render(
60
- <NProgress isAnimating>
63
+ const Progress = ({ isAnimating }) => (
64
+ <NProgress isAnimating={isAnimating}>
61
65
  {({ animationDuration, isFinished, progress }) => (
62
66
  <Container animationDuration={animationDuration} isFinished={isFinished}>
63
67
  <Bar animationDuration={animationDuration} progress={progress} />
64
68
  <Spinner />
65
69
  </Container>
66
70
  )}
67
- </NProgress>,
68
- document.getElementById('root')
71
+ </NProgress>
69
72
  )
70
73
  ```
71
74
 
72
- **HOC**
75
+ **Restarting**
73
76
 
74
- ```jsx
75
- import { withNProgress } from '@tanem/react-nprogress'
76
- import React from 'react'
77
- import { render } from 'react-dom'
77
+ Both patterns leave the bar mounted between runs, and `progress` returns to `minimum` when it starts again. A bar that transitions `margin-left` or `transform` therefore animates backwards from where it finished, in full view, before it starts trickling forward. Back to back navigations hit this every time.
78
78
 
79
- import Bar from './Bar'
80
- import Container from './Container'
81
- import Spinner from './Spinner'
79
+ Change a `key` on the bar whenever it starts, so React mounts a fresh element at `minimum` instead:
82
80
 
83
- const Inner = ({ animationDuration, isFinished, progress }) => (
84
- <Container animationDuration={animationDuration} isFinished={isFinished}>
85
- <Bar animationDuration={animationDuration} progress={progress} />
86
- <Spinner />
87
- </Container>
88
- )
81
+ ```jsx
82
+ const [state, setState] = useState({ isAnimating: false, key: 0 })
89
83
 
90
- const Enhanced = withNProgress(Inner)
84
+ const start = () => {
85
+ setState((prevState) => ({ isAnimating: true, key: prevState.key ^ 1 }))
86
+ }
91
87
 
92
- render(<Enhanced isAnimating />, document.getElementById('root'))
88
+ return <Progress isAnimating={state.isAnimating} key={state.key} />
93
89
  ```
94
90
 
95
- ## Live Examples
96
-
97
- - HOC: [Source](https://github.com/tanem/react-nprogress/tree/master/examples/hoc) | [Sandbox](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/hoc)
98
- - Material UI: [Source](https://github.com/tanem/react-nprogress/tree/master/examples/material-ui) | [Sandbox](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/material-ui)
99
- - Multiple Instances: [Source](https://github.com/tanem/react-nprogress/tree/master/examples/multiple-instances) | [Sandbox](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/multiple-instances)
100
- - Next App Router: [Source](https://github.com/tanem/react-nprogress/tree/master/examples/next-app-router) | [Sandbox](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/next-app-router)
101
- - Next Pages Router: [Source](https://github.com/tanem/react-nprogress/tree/master/examples/next-pages-router) | [Sandbox](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/next-pages-router)
102
- - Original Design: [Source](https://github.com/tanem/react-nprogress/tree/master/examples/original-design) | [Sandbox](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/original-design)
103
- - Plain JS: [Source](https://github.com/tanem/react-nprogress/tree/master/examples/plain-js) | [Sandbox](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/plain-js)
104
- - React Router: [Source](https://github.com/tanem/react-nprogress/tree/master/examples/react-router) | [Sandbox](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/react-router)
105
- - Render Props: [Source](https://github.com/tanem/react-nprogress/tree/master/examples/render-props) | [Sandbox](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/render-props)
106
- - UMD Build (Development): [Source](https://github.com/tanem/react-nprogress/tree/master/examples/umd-dev) | [Sandbox](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/umd-dev)
107
- - UMD Build (Production): [Source](https://github.com/tanem/react-nprogress/tree/master/examples/umd-prod) | [Sandbox](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/umd-prod)
91
+ Every entry in [Live Examples](#live-examples) does this. Dropping the transition while `isFinished` is not an alternative: `isFinished` is already `false` by the time `progress` resets, so the transition is back on for the step that moves the bar.
108
92
 
109
93
  ## API
110
94
 
111
- **Props**
112
-
113
- - `animationDuration` - _Optional_ Number indicating the animation duration in `ms`. Defaults to `200`.
114
- - `incrementDuration` - _Optional_ Number indicating the length of time between progress bar increments in `ms`. Defaults to `200`.
115
- - `isAnimating` - _Optional_ Boolean indicating if the progress bar is animating. Defaults to `false`.
116
- - `minimum` - _Optional_ Number between `0` and `1` indicating the minimum value of the progress bar. Defaults to `0.08`.
95
+ The package exports one hook and one component. Both take the same [options](#options) and produce the same [values](#return-value), so the choice between them is a matter of which pattern suits the calling code. Both shapes are exported as types, for typing code that wraps either entry point:
117
96
 
118
- **Hook Example**
97
+ ```ts
98
+ import type { NProgressOptions, NProgressState } from '@tanem/react-nprogress'
99
+ ```
119
100
 
120
- ```jsx
121
- const Progress = ({
122
- animationDuration,
123
- incrementDuration,
124
- isAnimating,
125
- minimum
126
- }) => {
127
- const { isFinished, progress } = useNProgress({
128
- animationDuration,
129
- incrementDuration,
130
- isAnimating,
131
- minimum
132
- })
101
+ ### `useNProgress`
133
102
 
134
- return (
135
- <Container animationDuration={animationDuration} isFinished={isFinished}>
136
- <Bar animationDuration={animationDuration} progress={progress} />
137
- <Spinner />
138
- </Container>
139
- )
140
- }
103
+ Returns the state of one progress bar. Call it once per bar: two calls, or two mounted `NProgress` components, track their progress independently.
141
104
 
142
- <Progress
143
- animationDuration={300}
144
- incrementDuration={500}
145
- isAnimating
146
- minimum={0.1}
147
- />
105
+ ```jsx
106
+ const { animationDuration, isFinished, progress } = useNProgress({
107
+ animationDuration: 300,
108
+ increment: (progress) => progress + 0.01,
109
+ incrementDuration: 500,
110
+ isAnimating: true,
111
+ minimum: 0.1,
112
+ })
148
113
  ```
149
114
 
150
- **Render Props Example**
115
+ ### `NProgress`
116
+
117
+ Takes the options as props and calls `children` with the values the hook returns. `children` is required and must return a React element.
151
118
 
152
119
  ```jsx
153
120
  <NProgress
154
121
  animationDuration={300}
122
+ increment={(progress) => progress + 0.01}
155
123
  incrementDuration={500}
156
124
  isAnimating
157
125
  minimum={0.1}
158
126
  >
159
- {({ animationDuration, isFinished, progress }) => (
160
- <Container animationDuration={animationDuration} isFinished={isFinished}>
161
- <Bar animationDuration={animationDuration} progress={progress} />
162
- <Spinner />
163
- </Container>
127
+ {({ animationDuration, progress }) => (
128
+ <Bar animationDuration={animationDuration} progress={progress} />
164
129
  )}
165
130
  </NProgress>
166
131
  ```
167
132
 
168
- **HOC Example**
133
+ ### Options
169
134
 
170
- ```jsx
171
- const Inner = ({ animationDuration, isFinished, progress }) => (
172
- <Container animationDuration={animationDuration} isFinished={isFinished}>
173
- <Bar animationDuration={animationDuration} progress={progress} />
174
- <Spinner />
175
- </Container>
176
- )
135
+ All five options are optional. The type is `NProgressOptions`.
177
136
 
178
- const Enhanced = withNProgress(Inner)
137
+ | Option | Type | Default |
138
+ | ----------------------------------------- | ------------------------------ | -------------- |
139
+ | [`animationDuration`](#animationduration) | `number` | `200` |
140
+ | [`increment`](#increment) | `(progress: number) => number` | tiered trickle |
141
+ | [`incrementDuration`](#incrementduration) | `number` | `200` |
142
+ | [`isAnimating`](#isanimating) | `boolean` | `false` |
143
+ | [`minimum`](#minimum) | `number` | `0.08` |
179
144
 
180
- <Enhanced
181
- animationDuration={300}
182
- incrementDuration={500}
183
- isAnimating
184
- minimum={0.1}
185
- />
186
- ```
145
+ #### `animationDuration`
187
146
 
188
- ## Installation
147
+ Milliseconds the bar is given to animate out once it completes. `progress` reaches `1` as soon as `isAnimating` goes `false`, and `isFinished` follows this many milliseconds later, leaving that window for the exit transition. The value is also returned unchanged, so a single number drives both the timing and the CSS transitions.
189
148
 
149
+ #### `increment`
150
+
151
+ Size of each trickle step. The function is called with the current `progress` and returns the next value. The default is the tiered curve nprogress uses: `+0.1` below `0.2`, then `+0.04`, `+0.02`, and `+0.005` as `progress` grows, held at a ceiling of `0.994` so the bar never looks complete before it is.
152
+
153
+ The return value is clamped to between `minimum` and `1`, and nothing else. A custom function therefore owns its own ceiling. Leave it short of `1`, since reaching `1` is what completion means, and let `isAnimating` going `false` take the bar the rest of the way.
154
+
155
+ Returning a random amount is fine, but keep the function free of other side effects. It runs inside a React state update, and StrictMode calls it twice per increment in development. This trickles a random amount of at most `0.02` every 800ms, which is how nprogress `0.2.0` paces itself:
156
+
157
+ ```jsx
158
+ const { progress } = useNProgress({
159
+ increment: (progress) => Math.min(progress + Math.random() * 0.02, 0.994),
160
+ incrementDuration: 800,
161
+ isAnimating,
162
+ })
190
163
  ```
191
- $ npm install @tanem/react-nprogress
192
- ```
193
164
 
194
- UMD builds are also available for use with pre-React 19 via [unpkg](https://unpkg.com/):
165
+ `0.2.0` also transitions the bar with `ease` where master uses `linear`. Easing lives in your renderer's CSS, so match it there if you want the rest of that look. The [Classic 0.2.0](https://github.com/tanem/react-nprogress/tree/master/examples/classic-020) example puts both together.
166
+
167
+ A new function identity on every render is fine too: passing an inline function does not restart the trickle timer. The next increment uses the latest function.
168
+
169
+ #### `incrementDuration`
170
+
171
+ Milliseconds between increments while the bar is animating. It controls the trickle pacing only. Step size is [`increment`](#increment).
172
+
173
+ #### `isAnimating`
174
+
175
+ Whether the bar is running. Going `true` starts it, going `false` completes it. Completion is what drives the final state: `progress` is set to `1`, and `isFinished` becomes `true` `animationDuration` milliseconds later.
176
+
177
+ #### `minimum`
178
+
179
+ Lower bound for `progress`, between `0` and `1`. The bar first appears at this value, then trickles up from there. Changing it while the bar is animating does not rewind the bar. Progress holds where it is, and the new bound applies from the next increment.
195
180
 
196
- - https://unpkg.com/@tanem/react-nprogress/dist/react-nprogress.umd.development.js
197
- - https://unpkg.com/@tanem/react-nprogress/dist/react-nprogress.umd.production.js
181
+ ### Return Value
198
182
 
199
- For the non-minified development version, make sure you have already included:
183
+ `useNProgress` returns these values, and `NProgress` passes the same object to `children`. The type is `NProgressState`.
200
184
 
201
- - [`React`](https://unpkg.com/react@18/umd/react.development.js)
202
- - [`ReactDOM`](https://unpkg.com/react-dom@18/umd/react-dom.development.js)
185
+ | Value | Type | Description |
186
+ | ------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
187
+ | `animationDuration` | `number` | The `animationDuration` option, passed through so rendering code can transition with it. |
188
+ | `isFinished` | `boolean` | `true` before the bar starts and again once it has animated out. `false` from when `isAnimating` goes `true` until `animationDuration` after it goes `false`. |
189
+ | `progress` | `number` | Starts at `0`, appears at `minimum` when the bar starts, then trickles up by [`increment`](#increment) and goes to `1` on completion. |
190
+
191
+ ## Live Examples
192
+
193
+ | Example | Sandbox |
194
+ | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------ |
195
+ | [Classic 0.2.0](https://github.com/tanem/react-nprogress/tree/master/examples/classic-020) | [Open](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/classic-020) |
196
+ | [Material UI](https://github.com/tanem/react-nprogress/tree/master/examples/material-ui) | [Open](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/material-ui) |
197
+ | [Multiple Instances](https://github.com/tanem/react-nprogress/tree/master/examples/multiple-instances) | [Open](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/multiple-instances) |
198
+ | [Next App Router](https://github.com/tanem/react-nprogress/tree/master/examples/next-app-router) | [Open](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/next-app-router) |
199
+ | [Next Pages Router](https://github.com/tanem/react-nprogress/tree/master/examples/next-pages-router) | [Open](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/next-pages-router) |
200
+ | [Original Design](https://github.com/tanem/react-nprogress/tree/master/examples/original-design) | [Open](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/original-design) |
201
+ | [Plain JS](https://github.com/tanem/react-nprogress/tree/master/examples/plain-js) | [Open](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/plain-js) |
202
+ | [React Router](https://github.com/tanem/react-nprogress/tree/master/examples/react-router) | [Open](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/react-router) |
203
+ | [Render Props](https://github.com/tanem/react-nprogress/tree/master/examples/render-props) | [Open](https://codesandbox.io/p/devbox/github/tanem/react-nprogress/tree/master/examples/render-props) |
204
+
205
+ ## Installation
206
+
207
+ ```
208
+ $ npm install @tanem/react-nprogress
209
+ ```
203
210
 
204
- For the minified production version, make sure you have already included:
211
+ ## Contributing
205
212
 
206
- - [`React`](https://unpkg.com/react@18/umd/react.production.min.js)
207
- - [`ReactDOM`](https://unpkg.com/react-dom@18/umd/react-dom.production.min.js)
213
+ Issues and pull requests are welcome. The development loop is `npm run test:src`, and `npm test` runs the full suite. Repository conventions, for humans and coding agents alike, live in [`AGENTS.md`](AGENTS.md).
208
214
 
209
215
  ## License
210
216
 
@@ -0,0 +1,124 @@
1
+ "use client";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ let react = require("react");
4
+ //#region src/clamp.ts
5
+ const clamp = (num, lower, upper) => {
6
+ num = num <= upper ? num : upper;
7
+ num = num >= lower ? num : lower;
8
+ return num;
9
+ };
10
+ //#endregion
11
+ //#region src/createTimeout.ts
12
+ const createTimeout = () => {
13
+ let handle;
14
+ const cancel = () => {
15
+ if (handle !== void 0) window.cancelAnimationFrame(handle);
16
+ };
17
+ const schedule = (callback, delay) => {
18
+ cancel();
19
+ let deltaTime;
20
+ let start;
21
+ const frame = (time) => {
22
+ start = start || time;
23
+ deltaTime = time - start;
24
+ if (deltaTime > delay) {
25
+ callback();
26
+ return;
27
+ }
28
+ handle = window.requestAnimationFrame(frame);
29
+ };
30
+ handle = window.requestAnimationFrame(frame);
31
+ };
32
+ return {
33
+ cancel,
34
+ schedule
35
+ };
36
+ };
37
+ //#endregion
38
+ //#region src/increment.ts
39
+ const increment = (progress) => {
40
+ let amount = 0;
41
+ if (progress >= 0 && progress < .2) amount = .1;
42
+ else if (progress >= .2 && progress < .5) amount = .04;
43
+ else if (progress >= .5 && progress < .8) amount = .02;
44
+ else if (progress >= .8 && progress < .99) amount = .005;
45
+ return clamp(progress + amount, 0, .994);
46
+ };
47
+ //#endregion
48
+ //#region src/useNProgress.tsx
49
+ const initialState = {
50
+ phase: "idle",
51
+ progress: 0
52
+ };
53
+ const reducer = (state, action) => {
54
+ switch (action.type) {
55
+ case "complete": return state.phase === "animating" ? {
56
+ phase: "completing",
57
+ progress: 1
58
+ } : state;
59
+ case "finish": return {
60
+ phase: "finished",
61
+ progress: 1
62
+ };
63
+ case "start": return state.phase === "animating" ? state : {
64
+ phase: "animating",
65
+ progress: clamp(0, action.minimum, 1)
66
+ };
67
+ case "trickle": return {
68
+ ...state,
69
+ progress: clamp(action.increment(state.progress), action.minimum, 1)
70
+ };
71
+ }
72
+ };
73
+ const useNProgress = ({ animationDuration = 200, increment: increment$1 = increment, incrementDuration = 200, isAnimating = false, minimum = .08 } = {}) => {
74
+ const [{ phase, progress }, dispatch] = (0, react.useReducer)(reducer, initialState);
75
+ const incrementRef = (0, react.useRef)(increment$1);
76
+ (0, react.useEffect)(() => {
77
+ incrementRef.current = increment$1;
78
+ });
79
+ (0, react.useEffect)(() => {
80
+ dispatch(isAnimating ? {
81
+ minimum,
82
+ type: "start"
83
+ } : { type: "complete" });
84
+ }, [isAnimating, minimum]);
85
+ (0, react.useEffect)(() => {
86
+ if (phase !== "animating") return;
87
+ const timeout = createTimeout();
88
+ const trickle = () => {
89
+ dispatch({
90
+ increment: incrementRef.current,
91
+ minimum,
92
+ type: "trickle"
93
+ });
94
+ timeout.schedule(trickle, incrementDuration);
95
+ };
96
+ timeout.schedule(trickle, incrementDuration);
97
+ return () => timeout.cancel();
98
+ }, [
99
+ incrementDuration,
100
+ minimum,
101
+ phase
102
+ ]);
103
+ (0, react.useEffect)(() => {
104
+ if (phase !== "completing") return;
105
+ const timeout = createTimeout();
106
+ timeout.schedule(() => dispatch({ type: "finish" }), animationDuration);
107
+ return () => timeout.cancel();
108
+ }, [animationDuration, phase]);
109
+ return {
110
+ animationDuration,
111
+ isFinished: phase === "finished" || phase === "idle",
112
+ progress
113
+ };
114
+ };
115
+ //#endregion
116
+ //#region src/NProgress.tsx
117
+ const NProgress = ({ children, ...restProps }) => {
118
+ return children(useNProgress(restProps));
119
+ };
120
+ //#endregion
121
+ exports.NProgress = NProgress;
122
+ exports.useNProgress = useNProgress;
123
+
124
+ //# sourceMappingURL=react-nprogress.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-nprogress.cjs","names":["defaultIncrement","useReducer","useRef","increment"],"sources":["../src/clamp.ts","../src/createTimeout.ts","../src/increment.ts","../src/useNProgress.tsx","../src/NProgress.tsx"],"sourcesContent":["export const clamp = (num: number, lower: number, upper: number): number => {\n num = num <= upper ? num : upper\n num = num >= lower ? num : lower\n return num\n}\n","// Uses requestAnimationFrame rather than setTimeout for smoother animation\n// timing. Note that rAF is throttled or paused in background tabs, so progress\n// will stall when the tab is hidden and resume when it regains focus.\nexport const createTimeout = () => {\n let handle: number | undefined\n\n const cancel = (): void => {\n if (handle !== undefined) {\n window.cancelAnimationFrame(handle)\n }\n }\n\n const schedule = (callback: () => void, delay: number): void => {\n cancel()\n\n let deltaTime\n let start: number | undefined\n const frame: FrameRequestCallback = (time) => {\n start = start || time\n deltaTime = time - start\n if (deltaTime > delay) {\n callback()\n return\n }\n handle = window.requestAnimationFrame(frame)\n }\n\n handle = window.requestAnimationFrame(frame)\n }\n\n return {\n cancel,\n schedule,\n }\n}\n","import { clamp } from './clamp'\n\nexport const increment = (progress: number): number => {\n let amount = 0\n\n if (progress >= 0 && progress < 0.2) {\n amount = 0.1\n } else if (progress >= 0.2 && progress < 0.5) {\n amount = 0.04\n } else if (progress >= 0.5 && progress < 0.8) {\n amount = 0.02\n } else if (progress >= 0.8 && progress < 0.99) {\n amount = 0.005\n }\n\n return clamp(progress + amount, 0, 0.994)\n}\n","import { useEffect, useReducer, useRef } from 'react'\n\nimport { clamp } from './clamp'\nimport { createTimeout } from './createTimeout'\nimport { increment as defaultIncrement } from './increment'\nimport type { NProgressOptions, NProgressState } from './types'\n\n// A four-phase state machine. `idle` and `finished` both report\n// `isFinished: true` and differ only in the progress they hold, so the phase,\n// not `isFinished`, is what decides which transitions and timers apply.\ntype Phase = 'animating' | 'completing' | 'finished' | 'idle'\n\ninterface State {\n phase: Phase\n progress: number\n}\n\ntype Action =\n | {\n increment: (progress: number) => number\n minimum: number\n type: 'trickle'\n }\n | { minimum: number; type: 'start' }\n | { type: 'complete' }\n | { type: 'finish' }\n\nconst initialState: State = {\n phase: 'idle',\n progress: 0,\n}\n\nconst reducer = (state: State, action: Action): State => {\n switch (action.type) {\n case 'complete':\n // The original nprogress `done()` computes a random progress jump before\n // animating to 1, but its queue runs both steps in the same tick, so the\n // jump's CSS is overwritten before paint and never renders. Omitting the\n // jump changes nothing visually.\n //\n // Ignored unless an animation is actually running, which is what makes a\n // StrictMode double-mount a no-op rather than a spurious completion.\n return state.phase === 'animating'\n ? { phase: 'completing', progress: 1 }\n : state\n\n case 'finish':\n return { phase: 'finished', progress: 1 }\n\n case 'start':\n // Matches the original nprogress `start()`, which calls set(0) and so\n // paints first at `minimum` before any trickle runs.\n //\n // Guarded the same way as `complete`, and for the same reason: a repeat\n // dispatch against a running animation must not rewind the bar. That\n // happens whenever `minimum` changes mid-animation, as well as on a\n // StrictMode double-mount.\n return state.phase === 'animating'\n ? state\n : {\n phase: 'animating',\n progress: clamp(0, action.minimum, 1),\n }\n\n case 'trickle':\n // Clamped here rather than trusted from the increment function, so a\n // custom one cannot take the bar outside the documented range. Stopping\n // short of 1 is that function's own business: 1 is what completion\n // means.\n return {\n ...state,\n progress: clamp(action.increment(state.progress), action.minimum, 1),\n }\n }\n}\n\nexport const useNProgress = ({\n animationDuration = 200,\n increment = defaultIncrement,\n incrementDuration = 200,\n isAnimating = false,\n minimum = 0.08,\n}: NProgressOptions = {}): NProgressState => {\n const [{ phase, progress }, dispatch] = useReducer(reducer, initialState)\n\n // Held in a ref so the trickle timer can read the latest increment function\n // without listing it as a dependency. Consumers commonly pass an inline\n // function, whose identity changes every render; depending on it directly\n // would cancel and recreate the timer each time, and a render loop faster\n // than `incrementDuration` would stop the bar advancing altogether.\n const incrementRef = useRef(increment)\n useEffect(() => {\n incrementRef.current = increment\n })\n\n useEffect(() => {\n dispatch(isAnimating ? { minimum, type: 'start' } : { type: 'complete' })\n }, [isAnimating, minimum])\n\n // A timer per running phase, rather than one effect branching over both.\n // Each then depends only on the options its own phase reads, so changing an\n // option the running phase ignores cannot cancel its timer. Both are keyed\n // on the phase rather than on progress, so trickling does not tear down and\n // recreate the timer mid-animation.\n useEffect(() => {\n if (phase !== 'animating') {\n return\n }\n\n const timeout = createTimeout()\n\n const trickle = () => {\n dispatch({ increment: incrementRef.current, minimum, type: 'trickle' })\n timeout.schedule(trickle, incrementDuration)\n }\n timeout.schedule(trickle, incrementDuration)\n\n return () => timeout.cancel()\n }, [incrementDuration, minimum, phase])\n\n useEffect(() => {\n if (phase !== 'completing') {\n return\n }\n\n const timeout = createTimeout()\n timeout.schedule(() => dispatch({ type: 'finish' }), animationDuration)\n\n return () => timeout.cancel()\n }, [animationDuration, phase])\n\n return {\n animationDuration,\n isFinished: phase === 'finished' || phase === 'idle',\n progress,\n }\n}\n","import type { FC, ReactElement } from 'react'\n\nimport type { NProgressOptions, NProgressState } from './types'\nimport { useNProgress } from './useNProgress'\n\ntype Props = NProgressOptions & {\n children: (renderProps: NProgressState) => ReactElement\n}\n\nexport const NProgress: FC<Props> = ({ children, ...restProps }: Props) => {\n const renderProps = useNProgress(restProps)\n return children(renderProps)\n}\n"],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { FC, ReactElement } from "react";
2
+ //#region src/types.d.ts
3
+ interface NProgressOptions {
4
+ animationDuration?: number;
5
+ increment?: (progress: number) => number;
6
+ incrementDuration?: number;
7
+ isAnimating?: boolean;
8
+ minimum?: number;
9
+ }
10
+ interface NProgressState {
11
+ animationDuration: number;
12
+ isFinished: boolean;
13
+ progress: number;
14
+ }
15
+ //#endregion
16
+ //#region src/NProgress.d.ts
17
+ type Props = NProgressOptions & {
18
+ children: (renderProps: NProgressState) => ReactElement;
19
+ };
20
+ declare const NProgress: FC<Props>;
21
+ //#endregion
22
+ //#region src/useNProgress.d.ts
23
+ declare const useNProgress: ({ animationDuration, increment, incrementDuration, isAnimating, minimum }?: NProgressOptions) => NProgressState;
24
+ //#endregion
25
+ export { NProgress, type NProgressOptions, type NProgressState, useNProgress };
26
+ //# sourceMappingURL=react-nprogress.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-nprogress.d.cts","names":[],"sources":["../src/types.ts","../src/NProgress.tsx","../src/useNProgress.tsx"],"mappings":";;UAAiB;EACf;EACA,aAAa;EACb;EACA;EACA;;UAGe;EACf;EACA;EACA;;;;KCNG,QAAQ;EACX,WAAW,aAAa,mBAAmB;;cAGhC,WAAW,GAAG;;;cCmEd,iBAAgB,mBAAA,WAAA,mBAAA,aAAA,YAM1B,qBAAwB"}
@@ -0,0 +1,26 @@
1
+ import { FC, ReactElement } from "react";
2
+ //#region src/types.d.ts
3
+ interface NProgressOptions {
4
+ animationDuration?: number;
5
+ increment?: (progress: number) => number;
6
+ incrementDuration?: number;
7
+ isAnimating?: boolean;
8
+ minimum?: number;
9
+ }
10
+ interface NProgressState {
11
+ animationDuration: number;
12
+ isFinished: boolean;
13
+ progress: number;
14
+ }
15
+ //#endregion
16
+ //#region src/NProgress.d.ts
17
+ type Props = NProgressOptions & {
18
+ children: (renderProps: NProgressState) => ReactElement;
19
+ };
20
+ declare const NProgress: FC<Props>;
21
+ //#endregion
22
+ //#region src/useNProgress.d.ts
23
+ declare const useNProgress: ({ animationDuration, increment, incrementDuration, isAnimating, minimum }?: NProgressOptions) => NProgressState;
24
+ //#endregion
25
+ export { NProgress, type NProgressOptions, type NProgressState, useNProgress };
26
+ //# sourceMappingURL=react-nprogress.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-nprogress.d.mts","names":[],"sources":["../src/types.ts","../src/NProgress.tsx","../src/useNProgress.tsx"],"mappings":";;UAAiB;EACf;EACA,aAAa;EACb;EACA;EACA;;UAGe;EACf;EACA;EACA;;;;KCNG,QAAQ;EACX,WAAW,aAAa,mBAAmB;;cAGhC,WAAW,GAAG;;;cCmEd,iBAAgB,mBAAA,WAAA,mBAAA,aAAA,YAM1B,qBAAwB"}
@@ -0,0 +1,122 @@
1
+ "use client";
2
+ import { useEffect, useReducer, useRef } from "react";
3
+ //#region src/clamp.ts
4
+ const clamp = (num, lower, upper) => {
5
+ num = num <= upper ? num : upper;
6
+ num = num >= lower ? num : lower;
7
+ return num;
8
+ };
9
+ //#endregion
10
+ //#region src/createTimeout.ts
11
+ const createTimeout = () => {
12
+ let handle;
13
+ const cancel = () => {
14
+ if (handle !== void 0) window.cancelAnimationFrame(handle);
15
+ };
16
+ const schedule = (callback, delay) => {
17
+ cancel();
18
+ let deltaTime;
19
+ let start;
20
+ const frame = (time) => {
21
+ start = start || time;
22
+ deltaTime = time - start;
23
+ if (deltaTime > delay) {
24
+ callback();
25
+ return;
26
+ }
27
+ handle = window.requestAnimationFrame(frame);
28
+ };
29
+ handle = window.requestAnimationFrame(frame);
30
+ };
31
+ return {
32
+ cancel,
33
+ schedule
34
+ };
35
+ };
36
+ //#endregion
37
+ //#region src/increment.ts
38
+ const increment = (progress) => {
39
+ let amount = 0;
40
+ if (progress >= 0 && progress < .2) amount = .1;
41
+ else if (progress >= .2 && progress < .5) amount = .04;
42
+ else if (progress >= .5 && progress < .8) amount = .02;
43
+ else if (progress >= .8 && progress < .99) amount = .005;
44
+ return clamp(progress + amount, 0, .994);
45
+ };
46
+ //#endregion
47
+ //#region src/useNProgress.tsx
48
+ const initialState = {
49
+ phase: "idle",
50
+ progress: 0
51
+ };
52
+ const reducer = (state, action) => {
53
+ switch (action.type) {
54
+ case "complete": return state.phase === "animating" ? {
55
+ phase: "completing",
56
+ progress: 1
57
+ } : state;
58
+ case "finish": return {
59
+ phase: "finished",
60
+ progress: 1
61
+ };
62
+ case "start": return state.phase === "animating" ? state : {
63
+ phase: "animating",
64
+ progress: clamp(0, action.minimum, 1)
65
+ };
66
+ case "trickle": return {
67
+ ...state,
68
+ progress: clamp(action.increment(state.progress), action.minimum, 1)
69
+ };
70
+ }
71
+ };
72
+ const useNProgress = ({ animationDuration = 200, increment: increment$1 = increment, incrementDuration = 200, isAnimating = false, minimum = .08 } = {}) => {
73
+ const [{ phase, progress }, dispatch] = useReducer(reducer, initialState);
74
+ const incrementRef = useRef(increment$1);
75
+ useEffect(() => {
76
+ incrementRef.current = increment$1;
77
+ });
78
+ useEffect(() => {
79
+ dispatch(isAnimating ? {
80
+ minimum,
81
+ type: "start"
82
+ } : { type: "complete" });
83
+ }, [isAnimating, minimum]);
84
+ useEffect(() => {
85
+ if (phase !== "animating") return;
86
+ const timeout = createTimeout();
87
+ const trickle = () => {
88
+ dispatch({
89
+ increment: incrementRef.current,
90
+ minimum,
91
+ type: "trickle"
92
+ });
93
+ timeout.schedule(trickle, incrementDuration);
94
+ };
95
+ timeout.schedule(trickle, incrementDuration);
96
+ return () => timeout.cancel();
97
+ }, [
98
+ incrementDuration,
99
+ minimum,
100
+ phase
101
+ ]);
102
+ useEffect(() => {
103
+ if (phase !== "completing") return;
104
+ const timeout = createTimeout();
105
+ timeout.schedule(() => dispatch({ type: "finish" }), animationDuration);
106
+ return () => timeout.cancel();
107
+ }, [animationDuration, phase]);
108
+ return {
109
+ animationDuration,
110
+ isFinished: phase === "finished" || phase === "idle",
111
+ progress
112
+ };
113
+ };
114
+ //#endregion
115
+ //#region src/NProgress.tsx
116
+ const NProgress = ({ children, ...restProps }) => {
117
+ return children(useNProgress(restProps));
118
+ };
119
+ //#endregion
120
+ export { NProgress, useNProgress };
121
+
122
+ //# sourceMappingURL=react-nprogress.mjs.map