react-top-progress 1.0.4 → 1.1.1
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.
- package/README.md +60 -78
- package/dist/index.d.mts +13 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.js +101 -7
- package/dist/index.mjs +97 -7
- package/package.json +9 -1
package/README.md
CHANGED
|
@@ -1,27 +1,23 @@
|
|
|
1
1
|
# react-top-progress
|
|
2
2
|
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+
|
|
3
7
|
**<a href="https://react-test-progress.vercel.app/" target="_blank">👉 View Live Demo</a>**
|
|
4
8
|
|
|
5
|
-
A lightweight, modern, and performant top loading progress bar for React. Built for seamless user experiences with zero dependencies
|
|
9
|
+
A lightweight, modern, and performant top loading progress bar for React. Built for seamless user experiences with **zero dependencies**!
|
|
6
10
|
|
|
7
11
|
Perfect for Next.js App Router, Vite, and standard SPA architectures.
|
|
8
12
|
|
|
9
|
-
## Features
|
|
10
|
-
|
|
11
|
-
- **0 Dependencies**: Tiny footprint (~1.8kb gzipped).
|
|
12
|
-
- **Advanced Loaders**: `continuous` and `static` start modes matching network logic.
|
|
13
|
-
- **Premium DX**: Controlled programmatically with simple global API hooks, or direct React `ref`.
|
|
14
|
-
- **Customizable**: Add gradients, background container colors, custom CSS classes, and glows.
|
|
15
|
-
- **Performant**: Uses `transform: translateZ(0)` hardware acceleration and `cubic-bezier` CSS transitions.
|
|
16
|
-
- **TypeScript ready**: Full types included.
|
|
17
|
-
|
|
18
13
|
## 🚀 Why react-top-progress?
|
|
19
14
|
|
|
20
15
|
- **SSR & App Router Safe**: Fully compatible with Next.js SSR & App Router natively
|
|
21
|
-
- **Framework Agnostic**: Works perfectly in React, Vite, CRA, Remix
|
|
16
|
+
- **Framework Agnostic**: Works perfectly in React, Vite, CRA, Remix, React Router
|
|
22
17
|
- **0 Dependencies**: No weird transitive bloat
|
|
23
|
-
- **📦 Tiny Bundle Size**: ~1.
|
|
18
|
+
- **📦 Tiny Bundle Size**: ~1.9kb gzipped (Tree-shakable)
|
|
24
19
|
- **Premium Aesthetics**: Smooth realistic loading animation with beautiful gradients & glows
|
|
20
|
+
- **Promise Integrations**: Auto-wrapping utilities like `withProgress` for API fetching
|
|
25
21
|
|
|
26
22
|
## Installation
|
|
27
23
|
|
|
@@ -29,50 +25,48 @@ Perfect for Next.js App Router, Vite, and standard SPA architectures.
|
|
|
29
25
|
npm install react-top-progress
|
|
30
26
|
```
|
|
31
27
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
yarn add react-top-progress
|
|
36
|
-
pnpm add react-top-progress
|
|
37
|
-
bun add react-top-progress
|
|
38
|
-
```
|
|
28
|
+
## Quick Start (Next.js / Vite / React)
|
|
39
29
|
|
|
40
|
-
|
|
30
|
+
### Method 1: The Global Provider (Recommended)
|
|
41
31
|
|
|
42
|
-
|
|
32
|
+
This approach automatically provides all routing configurations and is incredibly clean.
|
|
43
33
|
|
|
44
|
-
```
|
|
45
|
-
|
|
34
|
+
```jsx
|
|
35
|
+
import { ProgressProvider, useAutoProgress } from "react-top-progress";
|
|
46
36
|
|
|
47
|
-
|
|
37
|
+
export default function RootLayout({ children }) {
|
|
38
|
+
// Use generic auto-route progress detector or just trigger global effects
|
|
39
|
+
// Optional but recommended for easy routing coverage!
|
|
48
40
|
|
|
49
|
-
export default function Layout({ children }) {
|
|
50
41
|
return (
|
|
51
|
-
|
|
52
|
-
<TopProgress />
|
|
53
|
-
{/* Your Top Nav, Sidebar, etc. */}
|
|
42
|
+
<ProgressProvider color="#29D" height={3} shadow={true}>
|
|
54
43
|
{children}
|
|
55
|
-
|
|
44
|
+
</ProgressProvider>
|
|
56
45
|
);
|
|
57
46
|
}
|
|
58
47
|
```
|
|
59
48
|
|
|
60
|
-
|
|
49
|
+
### Method 2: Next.js App Router Generic Auto-Routing
|
|
61
50
|
|
|
62
|
-
|
|
63
|
-
Works flawlessly in both **JSX** and **TSX**!
|
|
51
|
+
Because Next.js App Router removed native router events, you can quickly auto-wire progress with the `useRouteProgress` hook, which intrinsically detects all link navigation globally using zero-external dependencies!
|
|
64
52
|
|
|
65
53
|
```jsx
|
|
66
|
-
|
|
54
|
+
"use client";
|
|
55
|
+
|
|
56
|
+
import { TopProgress, useRouteProgress } from "react-top-progress";
|
|
57
|
+
|
|
58
|
+
export default function Layout({ children }) {
|
|
59
|
+
useRouteProgress(); // Auto-detects clicks, routing events, and history pushState!
|
|
67
60
|
|
|
68
|
-
export default function RootLayout({ children }) {
|
|
69
61
|
return (
|
|
70
|
-
|
|
71
|
-
<
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
62
|
+
<>
|
|
63
|
+
<TopProgress
|
|
64
|
+
height={4}
|
|
65
|
+
color="linear-gradient(90deg, #ff5500, #ff0080)"
|
|
66
|
+
/>
|
|
67
|
+
{/* Your Top Nav, Sidebar, etc. */}
|
|
68
|
+
{children}
|
|
69
|
+
</>
|
|
76
70
|
);
|
|
77
71
|
}
|
|
78
72
|
```
|
|
@@ -87,64 +81,52 @@ You can trigger the loader from anywhere in your codebase by importing the funct
|
|
|
87
81
|
| `continuousStart(startingValue?, refreshRate?)` | `number`, `number` | Starts with a random value (20-30), then slowly ticks up (2-10) repetitively. Reaches max 90%. |
|
|
88
82
|
| `staticStart(startingValue?)` | `number` | Starts the loader with a random static value between 30-50, waiting for completion. |
|
|
89
83
|
| `complete()` / `finishProgress()` | | Instantly pushes the indicator to 100% and gracefully fades it out. |
|
|
84
|
+
| `resetProgress()` | | Instantly zeroes out and hides the progress bar without fading. |
|
|
90
85
|
| `increase(value)` | `number` | Manually increments the loader by a specific amount. |
|
|
91
86
|
| `decrease(value)` | `number` | Manually decrements the loader by a specific amount. |
|
|
92
87
|
| `setProgress(value)` | `number` | Hardsets to a specific progress percentage. |
|
|
93
88
|
| `getProgress()` | | Returns the current progress percentage (0 - 100). |
|
|
94
89
|
| `withProgress(promise)` | `Promise<T>` | Wraps an asynchronous action. `startProgress()` executes automatically before and completes automatically afterward. |
|
|
95
90
|
|
|
96
|
-
###
|
|
91
|
+
### Promise Wrapper Example
|
|
97
92
|
|
|
98
93
|
```jsx
|
|
99
|
-
import {
|
|
100
|
-
startProgress,
|
|
101
|
-
finishProgress,
|
|
102
|
-
withProgress,
|
|
103
|
-
} from "react-top-progress";
|
|
104
|
-
|
|
105
|
-
async function fetchData() {
|
|
106
|
-
startProgress("continuous");
|
|
107
|
-
try {
|
|
108
|
-
await apiCall();
|
|
109
|
-
} finally {
|
|
110
|
-
finishProgress(); // alias of complete()
|
|
111
|
-
}
|
|
112
|
-
}
|
|
94
|
+
import { withProgress } from "react-top-progress";
|
|
113
95
|
|
|
114
|
-
|
|
115
|
-
const loadProfile = () => withProgress(fetch("/api/profile"));
|
|
96
|
+
const data = await withProgress(fetch("/api/users"));
|
|
116
97
|
```
|
|
117
98
|
|
|
118
99
|
## Component Properties
|
|
119
100
|
|
|
120
101
|
You can customize `<TopProgress />` passing any of the following props:
|
|
121
102
|
|
|
122
|
-
| Property | Type | Default
|
|
123
|
-
| -------------------- | --------------- |
|
|
124
|
-
| `progress` | `number` |
|
|
125
|
-
| `color` | `string` | `"
|
|
126
|
-
| `height` | `number` | `
|
|
127
|
-
| `shadow` | `boolean` | `true`
|
|
128
|
-
| `background` | `string` | `"transparent"`
|
|
129
|
-
| `
|
|
130
|
-
| `loaderSpeed` | `number` | `500`
|
|
131
|
-
| `waitingTime` | `number` | `1000`
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
-
| `
|
|
103
|
+
| Property | Type | Default | Description |
|
|
104
|
+
| -------------------- | --------------- | -------------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
105
|
+
| `progress` | `number` | | Hardset the progress (0-100) if you want to bypass the internal store and control state yourself. |
|
|
106
|
+
| `color` | `string` | `"#29D"` | Background color of the bar. Accepts `linear-gradient(...)` or hex codes. |
|
|
107
|
+
| `height` | `number` | `3` | Height of the progress bar in pixels. |
|
|
108
|
+
| `shadow` | `boolean` | `true` | Appends a glorious trailing drop-glow peg matching the bar's color tracking its head. |
|
|
109
|
+
| `background` | `string` | `"transparent"` | Fills the container div's background layer under the progress element. |
|
|
110
|
+
| `transitionSpeed` | `number` | `200` | Fade transition time (ms) for the fade-out completion sequence. |
|
|
111
|
+
| `loaderSpeed` | `number` | `500` | Loader width transition speed (ms). |
|
|
112
|
+
| `waitingTime` | `number` | `1000` | The delay time (ms) loader waits at 100% width before fading entirely out. |
|
|
113
|
+
| `easing` | `string` | `"cubic-bezier(0.4, 0, 0.2, 1)"` | Customizable CSS animation timing path curve. |
|
|
114
|
+
| `style` | `CSSProperties` | | Inject custom JSX styles directly onto the loader element. |
|
|
115
|
+
| `className` | `string` | | Apply a specific custom CSS class to the loader element. |
|
|
116
|
+
| `containerStyle` | `CSSProperties` | | Configure inline styles for the fixed `<div />` wrapper container. |
|
|
117
|
+
| `containerClassName` | `string` | | Custom CSS class applied onto the wrapper container. |
|
|
118
|
+
| `onLoaderFinished` | `() => void` | | A callback function executing precisely when the loader fully hits 100% max width. |
|
|
137
119
|
|
|
138
120
|
## Compared to Alternatives
|
|
139
121
|
|
|
140
122
|
Developers need to know why to switch. Here is the breakdown:
|
|
141
123
|
|
|
142
|
-
| Library | Dependencies | SSR Safe | Bundle Size |
|
|
143
|
-
| ----------------------- | ---------------------- | -------- | ----------------- |
|
|
144
|
-
| `nprogress` | Old jQuery style logic | No | Larger |
|
|
145
|
-
| `nextjs-toploader` | Next-specific only | Yes | Medium |
|
|
146
|
-
| `react-top-loading-bar` | React mostly | Some | Medium |
|
|
147
|
-
| **react-top-progress** | **0 dependencies** | **Yes** | **Tiny (~1.
|
|
124
|
+
| Library | Dependencies | SSR Safe | Routing Bindings | Promise Wrap | Bundle Size |
|
|
125
|
+
| ----------------------- | ---------------------- | -------- | ----------------- | ------------ | ----------------- |
|
|
126
|
+
| `nprogress` | Old jQuery style logic | No | ❌ | ❌ | Larger |
|
|
127
|
+
| `nextjs-toploader` | Next-specific only | Yes | ✅ (Next.js) | ❌ | Medium |
|
|
128
|
+
| `react-top-loading-bar` | React mostly | Some | ❌ | ❌ | Medium |
|
|
129
|
+
| **react-top-progress** | **0 dependencies** | **Yes** | **✅ (Agnostic)** | **✅** | **Tiny (~1.9kb)** |
|
|
148
130
|
|
|
149
131
|
## Credits
|
|
150
132
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { CSSProperties } from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
3
|
|
|
3
4
|
interface TopProgressProps {
|
|
4
5
|
progress?: number;
|
|
@@ -10,8 +11,10 @@ interface TopProgressProps {
|
|
|
10
11
|
containerStyle?: CSSProperties;
|
|
11
12
|
shadowStyle?: CSSProperties;
|
|
12
13
|
transitionTime?: number;
|
|
14
|
+
transitionSpeed?: number;
|
|
13
15
|
loaderSpeed?: number;
|
|
14
16
|
waitingTime?: number;
|
|
17
|
+
easing?: string;
|
|
15
18
|
className?: string;
|
|
16
19
|
containerClassName?: string;
|
|
17
20
|
onLoaderFinished?: () => void;
|
|
@@ -31,6 +34,14 @@ interface TopProgressRef {
|
|
|
31
34
|
}
|
|
32
35
|
declare const TopProgress: React.ForwardRefExoticComponent<TopProgressProps & React.RefAttributes<TopProgressRef>>;
|
|
33
36
|
|
|
37
|
+
interface ProgressProviderProps extends TopProgressProps {
|
|
38
|
+
children: React.ReactNode;
|
|
39
|
+
}
|
|
40
|
+
declare const ProgressProvider: ({ children, ...props }: ProgressProviderProps) => react_jsx_runtime.JSX.Element;
|
|
41
|
+
|
|
42
|
+
declare const useAutoProgress: () => void;
|
|
43
|
+
declare const useRouteProgress: () => void;
|
|
44
|
+
|
|
34
45
|
declare const startProgress: (type?: "continuous" | "static") => void;
|
|
35
46
|
declare const continuousStart: (startingValue?: number, refreshRate?: number) => void;
|
|
36
47
|
declare const staticStart: (startingValue?: number) => void;
|
|
@@ -40,6 +51,7 @@ declare const increaseProgress: (value: number) => void;
|
|
|
40
51
|
declare const decreaseProgress: (value: number) => void;
|
|
41
52
|
declare const getProgress: () => number | null;
|
|
42
53
|
declare const setProgress: (value: number) => void;
|
|
54
|
+
declare const resetProgress: () => void;
|
|
43
55
|
declare const withProgress: <T>(promise: Promise<T>) => Promise<T>;
|
|
44
56
|
|
|
45
|
-
export { TopProgress, type TopProgressProps, type TopProgressRef, completeProgress, continuousStart, decreaseProgress, finishProgress, getProgress, increaseProgress, setProgress, startProgress, staticStart, withProgress };
|
|
57
|
+
export { ProgressProvider, type ProgressProviderProps, TopProgress, type TopProgressProps, type TopProgressRef, completeProgress, continuousStart, decreaseProgress, finishProgress, getProgress, increaseProgress, resetProgress, setProgress, startProgress, staticStart, useAutoProgress, useRouteProgress, withProgress };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { CSSProperties } from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
3
|
|
|
3
4
|
interface TopProgressProps {
|
|
4
5
|
progress?: number;
|
|
@@ -10,8 +11,10 @@ interface TopProgressProps {
|
|
|
10
11
|
containerStyle?: CSSProperties;
|
|
11
12
|
shadowStyle?: CSSProperties;
|
|
12
13
|
transitionTime?: number;
|
|
14
|
+
transitionSpeed?: number;
|
|
13
15
|
loaderSpeed?: number;
|
|
14
16
|
waitingTime?: number;
|
|
17
|
+
easing?: string;
|
|
15
18
|
className?: string;
|
|
16
19
|
containerClassName?: string;
|
|
17
20
|
onLoaderFinished?: () => void;
|
|
@@ -31,6 +34,14 @@ interface TopProgressRef {
|
|
|
31
34
|
}
|
|
32
35
|
declare const TopProgress: React.ForwardRefExoticComponent<TopProgressProps & React.RefAttributes<TopProgressRef>>;
|
|
33
36
|
|
|
37
|
+
interface ProgressProviderProps extends TopProgressProps {
|
|
38
|
+
children: React.ReactNode;
|
|
39
|
+
}
|
|
40
|
+
declare const ProgressProvider: ({ children, ...props }: ProgressProviderProps) => react_jsx_runtime.JSX.Element;
|
|
41
|
+
|
|
42
|
+
declare const useAutoProgress: () => void;
|
|
43
|
+
declare const useRouteProgress: () => void;
|
|
44
|
+
|
|
34
45
|
declare const startProgress: (type?: "continuous" | "static") => void;
|
|
35
46
|
declare const continuousStart: (startingValue?: number, refreshRate?: number) => void;
|
|
36
47
|
declare const staticStart: (startingValue?: number) => void;
|
|
@@ -40,6 +51,7 @@ declare const increaseProgress: (value: number) => void;
|
|
|
40
51
|
declare const decreaseProgress: (value: number) => void;
|
|
41
52
|
declare const getProgress: () => number | null;
|
|
42
53
|
declare const setProgress: (value: number) => void;
|
|
54
|
+
declare const resetProgress: () => void;
|
|
43
55
|
declare const withProgress: <T>(promise: Promise<T>) => Promise<T>;
|
|
44
56
|
|
|
45
|
-
export { TopProgress, type TopProgressProps, type TopProgressRef, completeProgress, continuousStart, decreaseProgress, finishProgress, getProgress, increaseProgress, setProgress, startProgress, staticStart, withProgress };
|
|
57
|
+
export { ProgressProvider, type ProgressProviderProps, TopProgress, type TopProgressProps, type TopProgressRef, completeProgress, continuousStart, decreaseProgress, finishProgress, getProgress, increaseProgress, resetProgress, setProgress, startProgress, staticStart, useAutoProgress, useRouteProgress, withProgress };
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
// src/index.ts
|
|
22
22
|
var index_exports = {};
|
|
23
23
|
__export(index_exports, {
|
|
24
|
+
ProgressProvider: () => ProgressProvider,
|
|
24
25
|
TopProgress: () => TopProgress,
|
|
25
26
|
completeProgress: () => completeProgress,
|
|
26
27
|
continuousStart: () => continuousStart,
|
|
@@ -28,9 +29,12 @@ __export(index_exports, {
|
|
|
28
29
|
finishProgress: () => finishProgress,
|
|
29
30
|
getProgress: () => getProgress,
|
|
30
31
|
increaseProgress: () => increaseProgress,
|
|
32
|
+
resetProgress: () => resetProgress,
|
|
31
33
|
setProgress: () => setProgress,
|
|
32
34
|
startProgress: () => startProgress,
|
|
33
35
|
staticStart: () => staticStart,
|
|
36
|
+
useAutoProgress: () => useAutoProgress,
|
|
37
|
+
useRouteProgress: () => useRouteProgress,
|
|
34
38
|
withProgress: () => withProgress
|
|
35
39
|
});
|
|
36
40
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -96,6 +100,11 @@ var ProgressStore = class {
|
|
|
96
100
|
this.notify();
|
|
97
101
|
}, this.config.waitingTime);
|
|
98
102
|
}
|
|
103
|
+
reset() {
|
|
104
|
+
this.cleanup();
|
|
105
|
+
this.value = null;
|
|
106
|
+
this.notify();
|
|
107
|
+
}
|
|
99
108
|
set(value) {
|
|
100
109
|
this.cleanup();
|
|
101
110
|
this.value = value;
|
|
@@ -139,6 +148,7 @@ var increaseProgress = (value) => progressStore.increase(value);
|
|
|
139
148
|
var decreaseProgress = (value) => progressStore.decrease(value);
|
|
140
149
|
var getProgress = () => progressStore.getProgress();
|
|
141
150
|
var setProgress = (value) => progressStore.set(value);
|
|
151
|
+
var resetProgress = () => progressStore.reset();
|
|
142
152
|
var withProgress = async (promise) => {
|
|
143
153
|
startProgress();
|
|
144
154
|
try {
|
|
@@ -156,16 +166,18 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
156
166
|
var TopProgress = (0, import_react.forwardRef)(
|
|
157
167
|
({
|
|
158
168
|
progress: controlledProgress,
|
|
159
|
-
color = "
|
|
169
|
+
color = "#29D",
|
|
160
170
|
shadow = true,
|
|
161
|
-
height =
|
|
171
|
+
height = 3,
|
|
162
172
|
background = "transparent",
|
|
163
173
|
style,
|
|
164
174
|
containerStyle,
|
|
165
175
|
shadowStyle,
|
|
166
|
-
transitionTime
|
|
176
|
+
transitionTime,
|
|
177
|
+
transitionSpeed = 200,
|
|
167
178
|
loaderSpeed = 500,
|
|
168
179
|
waitingTime = 1e3,
|
|
180
|
+
easing = "cubic-bezier(0.4, 0, 0.2, 1)",
|
|
169
181
|
className,
|
|
170
182
|
containerClassName,
|
|
171
183
|
onLoaderFinished,
|
|
@@ -177,6 +189,7 @@ var TopProgress = (0, import_react.forwardRef)(
|
|
|
177
189
|
const [internalProgress, setInternalProgress] = (0, import_react.useState)(
|
|
178
190
|
store.getValue()
|
|
179
191
|
);
|
|
192
|
+
const [mounted, setMounted] = (0, import_react.useState)(false);
|
|
180
193
|
(0, import_react.useImperativeHandle)(ref, () => ({
|
|
181
194
|
start: (type) => store.start(type),
|
|
182
195
|
continuousStart: (s, r) => store.continuousStart(s, r),
|
|
@@ -187,12 +200,14 @@ var TopProgress = (0, import_react.forwardRef)(
|
|
|
187
200
|
getProgress: () => store.getProgress(),
|
|
188
201
|
set: (v) => store.set(v)
|
|
189
202
|
}));
|
|
203
|
+
const fadeSpeed = transitionTime !== void 0 ? transitionTime : transitionSpeed;
|
|
190
204
|
(0, import_react.useEffect)(() => {
|
|
191
|
-
store.config.transitionTime =
|
|
205
|
+
store.config.transitionTime = fadeSpeed;
|
|
192
206
|
store.config.loaderSpeed = loaderSpeed;
|
|
193
207
|
store.config.waitingTime = waitingTime;
|
|
194
|
-
}, [
|
|
208
|
+
}, [fadeSpeed, loaderSpeed, waitingTime, store]);
|
|
195
209
|
(0, import_react.useEffect)(() => {
|
|
210
|
+
setMounted(true);
|
|
196
211
|
return store.subscribe(setInternalProgress);
|
|
197
212
|
}, [store]);
|
|
198
213
|
const progress = controlledProgress !== void 0 ? controlledProgress : internalProgress;
|
|
@@ -201,7 +216,7 @@ var TopProgress = (0, import_react.forwardRef)(
|
|
|
201
216
|
onLoaderFinished();
|
|
202
217
|
}
|
|
203
218
|
}, [progress, onLoaderFinished]);
|
|
204
|
-
if (progress === null) {
|
|
219
|
+
if (!mounted || progress === null) {
|
|
205
220
|
return null;
|
|
206
221
|
}
|
|
207
222
|
const isGradient = color.includes("gradient(");
|
|
@@ -231,7 +246,7 @@ var TopProgress = (0, import_react.forwardRef)(
|
|
|
231
246
|
width: `${progress}%`,
|
|
232
247
|
height: "100%",
|
|
233
248
|
...backgroundStyle,
|
|
234
|
-
transition: `width ${loaderSpeed}ms
|
|
249
|
+
transition: `width ${loaderSpeed}ms ${easing}, opacity ${fadeSpeed}ms ease`,
|
|
235
250
|
opacity: progress === 100 ? 0 : 1,
|
|
236
251
|
transform: "translateZ(0)",
|
|
237
252
|
...style
|
|
@@ -260,8 +275,84 @@ var TopProgress = (0, import_react.forwardRef)(
|
|
|
260
275
|
}
|
|
261
276
|
);
|
|
262
277
|
TopProgress.displayName = "TopProgress";
|
|
278
|
+
|
|
279
|
+
// src/ProgressProvider.tsx
|
|
280
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
281
|
+
var ProgressProvider = ({
|
|
282
|
+
children,
|
|
283
|
+
...props
|
|
284
|
+
}) => {
|
|
285
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
286
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(TopProgress, { ...props }),
|
|
287
|
+
children
|
|
288
|
+
] });
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
// src/hooks.ts
|
|
292
|
+
var import_react2 = require("react");
|
|
293
|
+
var useAutoProgress = () => {
|
|
294
|
+
(0, import_react2.useEffect)(() => {
|
|
295
|
+
startProgress();
|
|
296
|
+
return () => {
|
|
297
|
+
finishProgress();
|
|
298
|
+
};
|
|
299
|
+
}, []);
|
|
300
|
+
};
|
|
301
|
+
var useRouteProgress = () => {
|
|
302
|
+
(0, import_react2.useEffect)(() => {
|
|
303
|
+
const handleAnchorClick = (event) => {
|
|
304
|
+
const target = event.currentTarget;
|
|
305
|
+
if (!target.href || target.target === "_blank" || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || target.hasAttribute("download")) {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
try {
|
|
309
|
+
const targetUrl = new URL(target.href);
|
|
310
|
+
const currentUrl = new URL(window.location.href);
|
|
311
|
+
if (targetUrl.origin === currentUrl.origin && targetUrl.pathname !== currentUrl.pathname) {
|
|
312
|
+
startProgress();
|
|
313
|
+
}
|
|
314
|
+
} catch (err) {
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
const handleMutation = () => {
|
|
318
|
+
const anchors = document.querySelectorAll("a[href]");
|
|
319
|
+
anchors.forEach((anchor) => {
|
|
320
|
+
anchor.removeEventListener("click", handleAnchorClick);
|
|
321
|
+
anchor.addEventListener("click", handleAnchorClick);
|
|
322
|
+
});
|
|
323
|
+
};
|
|
324
|
+
const mutationObserver = new MutationObserver(handleMutation);
|
|
325
|
+
mutationObserver.observe(document.body, { childList: true, subtree: true });
|
|
326
|
+
handleMutation();
|
|
327
|
+
const originalPushState = window.history.pushState;
|
|
328
|
+
const originalReplaceState = window.history.replaceState;
|
|
329
|
+
window.history.pushState = function(...args) {
|
|
330
|
+
finishProgress();
|
|
331
|
+
return originalPushState.apply(this, args);
|
|
332
|
+
};
|
|
333
|
+
window.history.replaceState = function(...args) {
|
|
334
|
+
finishProgress();
|
|
335
|
+
return originalReplaceState.apply(this, args);
|
|
336
|
+
};
|
|
337
|
+
const handlePopState = () => {
|
|
338
|
+
finishProgress();
|
|
339
|
+
};
|
|
340
|
+
window.addEventListener("popstate", handlePopState);
|
|
341
|
+
return () => {
|
|
342
|
+
mutationObserver.disconnect();
|
|
343
|
+
const anchors = document.querySelectorAll("a[href]");
|
|
344
|
+
anchors.forEach((anchor) => {
|
|
345
|
+
anchor.removeEventListener("click", handleAnchorClick);
|
|
346
|
+
});
|
|
347
|
+
window.history.pushState = originalPushState;
|
|
348
|
+
window.history.replaceState = originalReplaceState;
|
|
349
|
+
window.removeEventListener("popstate", handlePopState);
|
|
350
|
+
};
|
|
351
|
+
}, []);
|
|
352
|
+
};
|
|
263
353
|
// Annotate the CommonJS export names for ESM import in node:
|
|
264
354
|
0 && (module.exports = {
|
|
355
|
+
ProgressProvider,
|
|
265
356
|
TopProgress,
|
|
266
357
|
completeProgress,
|
|
267
358
|
continuousStart,
|
|
@@ -269,8 +360,11 @@ TopProgress.displayName = "TopProgress";
|
|
|
269
360
|
finishProgress,
|
|
270
361
|
getProgress,
|
|
271
362
|
increaseProgress,
|
|
363
|
+
resetProgress,
|
|
272
364
|
setProgress,
|
|
273
365
|
startProgress,
|
|
274
366
|
staticStart,
|
|
367
|
+
useAutoProgress,
|
|
368
|
+
useRouteProgress,
|
|
275
369
|
withProgress
|
|
276
370
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -66,6 +66,11 @@ var ProgressStore = class {
|
|
|
66
66
|
this.notify();
|
|
67
67
|
}, this.config.waitingTime);
|
|
68
68
|
}
|
|
69
|
+
reset() {
|
|
70
|
+
this.cleanup();
|
|
71
|
+
this.value = null;
|
|
72
|
+
this.notify();
|
|
73
|
+
}
|
|
69
74
|
set(value) {
|
|
70
75
|
this.cleanup();
|
|
71
76
|
this.value = value;
|
|
@@ -109,6 +114,7 @@ var increaseProgress = (value) => progressStore.increase(value);
|
|
|
109
114
|
var decreaseProgress = (value) => progressStore.decrease(value);
|
|
110
115
|
var getProgress = () => progressStore.getProgress();
|
|
111
116
|
var setProgress = (value) => progressStore.set(value);
|
|
117
|
+
var resetProgress = () => progressStore.reset();
|
|
112
118
|
var withProgress = async (promise) => {
|
|
113
119
|
startProgress();
|
|
114
120
|
try {
|
|
@@ -126,16 +132,18 @@ import { jsx } from "react/jsx-runtime";
|
|
|
126
132
|
var TopProgress = forwardRef(
|
|
127
133
|
({
|
|
128
134
|
progress: controlledProgress,
|
|
129
|
-
color = "
|
|
135
|
+
color = "#29D",
|
|
130
136
|
shadow = true,
|
|
131
|
-
height =
|
|
137
|
+
height = 3,
|
|
132
138
|
background = "transparent",
|
|
133
139
|
style,
|
|
134
140
|
containerStyle,
|
|
135
141
|
shadowStyle,
|
|
136
|
-
transitionTime
|
|
142
|
+
transitionTime,
|
|
143
|
+
transitionSpeed = 200,
|
|
137
144
|
loaderSpeed = 500,
|
|
138
145
|
waitingTime = 1e3,
|
|
146
|
+
easing = "cubic-bezier(0.4, 0, 0.2, 1)",
|
|
139
147
|
className,
|
|
140
148
|
containerClassName,
|
|
141
149
|
onLoaderFinished,
|
|
@@ -147,6 +155,7 @@ var TopProgress = forwardRef(
|
|
|
147
155
|
const [internalProgress, setInternalProgress] = useState(
|
|
148
156
|
store.getValue()
|
|
149
157
|
);
|
|
158
|
+
const [mounted, setMounted] = useState(false);
|
|
150
159
|
useImperativeHandle(ref, () => ({
|
|
151
160
|
start: (type) => store.start(type),
|
|
152
161
|
continuousStart: (s, r) => store.continuousStart(s, r),
|
|
@@ -157,12 +166,14 @@ var TopProgress = forwardRef(
|
|
|
157
166
|
getProgress: () => store.getProgress(),
|
|
158
167
|
set: (v) => store.set(v)
|
|
159
168
|
}));
|
|
169
|
+
const fadeSpeed = transitionTime !== void 0 ? transitionTime : transitionSpeed;
|
|
160
170
|
useEffect(() => {
|
|
161
|
-
store.config.transitionTime =
|
|
171
|
+
store.config.transitionTime = fadeSpeed;
|
|
162
172
|
store.config.loaderSpeed = loaderSpeed;
|
|
163
173
|
store.config.waitingTime = waitingTime;
|
|
164
|
-
}, [
|
|
174
|
+
}, [fadeSpeed, loaderSpeed, waitingTime, store]);
|
|
165
175
|
useEffect(() => {
|
|
176
|
+
setMounted(true);
|
|
166
177
|
return store.subscribe(setInternalProgress);
|
|
167
178
|
}, [store]);
|
|
168
179
|
const progress = controlledProgress !== void 0 ? controlledProgress : internalProgress;
|
|
@@ -171,7 +182,7 @@ var TopProgress = forwardRef(
|
|
|
171
182
|
onLoaderFinished();
|
|
172
183
|
}
|
|
173
184
|
}, [progress, onLoaderFinished]);
|
|
174
|
-
if (progress === null) {
|
|
185
|
+
if (!mounted || progress === null) {
|
|
175
186
|
return null;
|
|
176
187
|
}
|
|
177
188
|
const isGradient = color.includes("gradient(");
|
|
@@ -201,7 +212,7 @@ var TopProgress = forwardRef(
|
|
|
201
212
|
width: `${progress}%`,
|
|
202
213
|
height: "100%",
|
|
203
214
|
...backgroundStyle,
|
|
204
|
-
transition: `width ${loaderSpeed}ms
|
|
215
|
+
transition: `width ${loaderSpeed}ms ${easing}, opacity ${fadeSpeed}ms ease`,
|
|
205
216
|
opacity: progress === 100 ? 0 : 1,
|
|
206
217
|
transform: "translateZ(0)",
|
|
207
218
|
...style
|
|
@@ -230,7 +241,83 @@ var TopProgress = forwardRef(
|
|
|
230
241
|
}
|
|
231
242
|
);
|
|
232
243
|
TopProgress.displayName = "TopProgress";
|
|
244
|
+
|
|
245
|
+
// src/ProgressProvider.tsx
|
|
246
|
+
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
247
|
+
var ProgressProvider = ({
|
|
248
|
+
children,
|
|
249
|
+
...props
|
|
250
|
+
}) => {
|
|
251
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
252
|
+
/* @__PURE__ */ jsx2(TopProgress, { ...props }),
|
|
253
|
+
children
|
|
254
|
+
] });
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
// src/hooks.ts
|
|
258
|
+
import { useEffect as useEffect2 } from "react";
|
|
259
|
+
var useAutoProgress = () => {
|
|
260
|
+
useEffect2(() => {
|
|
261
|
+
startProgress();
|
|
262
|
+
return () => {
|
|
263
|
+
finishProgress();
|
|
264
|
+
};
|
|
265
|
+
}, []);
|
|
266
|
+
};
|
|
267
|
+
var useRouteProgress = () => {
|
|
268
|
+
useEffect2(() => {
|
|
269
|
+
const handleAnchorClick = (event) => {
|
|
270
|
+
const target = event.currentTarget;
|
|
271
|
+
if (!target.href || target.target === "_blank" || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || target.hasAttribute("download")) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
try {
|
|
275
|
+
const targetUrl = new URL(target.href);
|
|
276
|
+
const currentUrl = new URL(window.location.href);
|
|
277
|
+
if (targetUrl.origin === currentUrl.origin && targetUrl.pathname !== currentUrl.pathname) {
|
|
278
|
+
startProgress();
|
|
279
|
+
}
|
|
280
|
+
} catch (err) {
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
const handleMutation = () => {
|
|
284
|
+
const anchors = document.querySelectorAll("a[href]");
|
|
285
|
+
anchors.forEach((anchor) => {
|
|
286
|
+
anchor.removeEventListener("click", handleAnchorClick);
|
|
287
|
+
anchor.addEventListener("click", handleAnchorClick);
|
|
288
|
+
});
|
|
289
|
+
};
|
|
290
|
+
const mutationObserver = new MutationObserver(handleMutation);
|
|
291
|
+
mutationObserver.observe(document.body, { childList: true, subtree: true });
|
|
292
|
+
handleMutation();
|
|
293
|
+
const originalPushState = window.history.pushState;
|
|
294
|
+
const originalReplaceState = window.history.replaceState;
|
|
295
|
+
window.history.pushState = function(...args) {
|
|
296
|
+
finishProgress();
|
|
297
|
+
return originalPushState.apply(this, args);
|
|
298
|
+
};
|
|
299
|
+
window.history.replaceState = function(...args) {
|
|
300
|
+
finishProgress();
|
|
301
|
+
return originalReplaceState.apply(this, args);
|
|
302
|
+
};
|
|
303
|
+
const handlePopState = () => {
|
|
304
|
+
finishProgress();
|
|
305
|
+
};
|
|
306
|
+
window.addEventListener("popstate", handlePopState);
|
|
307
|
+
return () => {
|
|
308
|
+
mutationObserver.disconnect();
|
|
309
|
+
const anchors = document.querySelectorAll("a[href]");
|
|
310
|
+
anchors.forEach((anchor) => {
|
|
311
|
+
anchor.removeEventListener("click", handleAnchorClick);
|
|
312
|
+
});
|
|
313
|
+
window.history.pushState = originalPushState;
|
|
314
|
+
window.history.replaceState = originalReplaceState;
|
|
315
|
+
window.removeEventListener("popstate", handlePopState);
|
|
316
|
+
};
|
|
317
|
+
}, []);
|
|
318
|
+
};
|
|
233
319
|
export {
|
|
320
|
+
ProgressProvider,
|
|
234
321
|
TopProgress,
|
|
235
322
|
completeProgress,
|
|
236
323
|
continuousStart,
|
|
@@ -238,8 +325,11 @@ export {
|
|
|
238
325
|
finishProgress,
|
|
239
326
|
getProgress,
|
|
240
327
|
increaseProgress,
|
|
328
|
+
resetProgress,
|
|
241
329
|
setProgress,
|
|
242
330
|
startProgress,
|
|
243
331
|
staticStart,
|
|
332
|
+
useAutoProgress,
|
|
333
|
+
useRouteProgress,
|
|
244
334
|
withProgress
|
|
245
335
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-top-progress",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "A lightweight modern top loading progress bar for React",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/harrymate22/react-top-progress.git"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/harrymate22/react-top-progress",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/harrymate22/react-top-progress/issues"
|
|
12
|
+
},
|
|
5
13
|
"main": "dist/index.js",
|
|
6
14
|
"module": "dist/index.mjs",
|
|
7
15
|
"types": "dist/index.d.ts",
|