react-top-progress 0.1.1 → 1.0.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 +59 -45
- package/demo_react_top_progress.webp +0 -0
- package/dist/index.d.mts +33 -4
- package/dist/index.d.ts +33 -4
- package/dist/index.js +180 -67
- package/dist/index.mjs +179 -68
- package/package.json +2 -2
- package/demo_react_top_progress.png +0 -0
package/README.md
CHANGED
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
# react-top-progress
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**<a href="https://react-test-progress.vercel.app/" target="_blank">👉 View Live Demo</a>**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
A lightweight, modern, and performant top loading progress bar for React. Built for seamless user experiences with zero dependencies!
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Perfect for Next.js App Router, Vite, and standard single-page applications.
|
|
7
|
+
Perfect for Next.js App Router, Vite, and standard SPA architectures.
|
|
10
8
|
|
|
11
9
|
## Features
|
|
12
10
|
|
|
13
|
-
- **0
|
|
14
|
-
- **
|
|
15
|
-
- **Premium DX**: Controlled programmatically with simple
|
|
16
|
-
- **
|
|
17
|
-
- **Performant**: Uses `transform` hardware acceleration and `cubic-bezier` transitions.
|
|
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.
|
|
18
16
|
- **TypeScript ready**: Full types included.
|
|
19
|
-
- **React 18+ & Next.js ready**: Contains `"use client"` where necessary.
|
|
20
17
|
|
|
21
18
|
## Installation
|
|
22
19
|
|
|
@@ -34,9 +31,7 @@ bun add react-top-progress
|
|
|
34
31
|
|
|
35
32
|
## Quick Start
|
|
36
33
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
At the top level of your application (like Next.js `app/layout.tsx` or Vite `src/App.tsx`), render the `<TopProgress />` component.
|
|
34
|
+
At the top level of your application (like Next.js `app/layout.tsx` or Vite `src/App.tsx`), render the component.
|
|
40
35
|
|
|
41
36
|
```tsx
|
|
42
37
|
import { TopProgress } from "react-top-progress";
|
|
@@ -53,52 +48,71 @@ export default function RootLayout({ children }) {
|
|
|
53
48
|
}
|
|
54
49
|
```
|
|
55
50
|
|
|
56
|
-
|
|
51
|
+
## Built-in Methods
|
|
57
52
|
|
|
58
|
-
|
|
53
|
+
You can trigger the loader from anywhere in your codebase by importing the functions globally, or via a React `ref` assigned to `<TopProgress ref={myRef} />`.
|
|
59
54
|
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
| Method | Parameters | Description |
|
|
56
|
+
| ----------------------------------------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
57
|
+
| `start(loaderType?)` | `"continuous" \| "static"` | Starts the loading indicator. Default is continuous. |
|
|
58
|
+
| `continuousStart(startingValue?, refreshRate?)` | `number`, `number` | Starts with a random value (20-30), then slowly ticks up (2-10) repetitively. Reaches max 90%. |
|
|
59
|
+
| `staticStart(startingValue?)` | `number` | Starts the loader with a random static value between 30-50, waiting for completion. |
|
|
60
|
+
| `complete()` / `finishProgress()` | | Instantly pushes the indicator to 100% and gracefully fades it out. |
|
|
61
|
+
| `increase(value)` | `number` | Manually increments the loader by a specific amount. |
|
|
62
|
+
| `decrease(value)` | `number` | Manually decrements the loader by a specific amount. |
|
|
63
|
+
| `setProgress(value)` | `number` | Hardsets to a specific progress percentage. |
|
|
64
|
+
| `getProgress()` | | Returns the current progress percentage (0 - 100). |
|
|
65
|
+
| `withProgress(promise)` | `Promise<T>` | Wraps an asynchronous action. `startProgress()` executes automatically before and completes automatically afterward. |
|
|
62
66
|
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
### Global Usage Example
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
import {
|
|
71
|
+
startProgress,
|
|
72
|
+
finishProgress,
|
|
73
|
+
withProgress,
|
|
74
|
+
} from "react-top-progress";
|
|
75
|
+
|
|
76
|
+
async function fetchData() {
|
|
77
|
+
startProgress("continuous");
|
|
65
78
|
try {
|
|
66
|
-
await
|
|
79
|
+
await apiCall();
|
|
67
80
|
} finally {
|
|
68
|
-
finishProgress();
|
|
81
|
+
finishProgress(); // alias of complete()
|
|
69
82
|
}
|
|
70
83
|
}
|
|
71
|
-
```
|
|
72
84
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
For an even better Developer Experience, simply wrap your promises securely with `withProgress`!
|
|
76
|
-
|
|
77
|
-
```tsx
|
|
78
|
-
import { withProgress } from "react-top-progress";
|
|
79
|
-
|
|
80
|
-
async function handleFetch() {
|
|
81
|
-
const data = await withProgress(fetch("/api/data"));
|
|
82
|
-
console.log(data);
|
|
83
|
-
}
|
|
85
|
+
// Or functionally wrap promises for ultimate DX:
|
|
86
|
+
const loadProfile = () => withProgress(fetch("/api/profile"));
|
|
84
87
|
```
|
|
85
88
|
|
|
86
|
-
##
|
|
89
|
+
## Component Properties
|
|
87
90
|
|
|
88
|
-
|
|
91
|
+
You can customize `<TopProgress />` passing any of the following props:
|
|
89
92
|
|
|
90
|
-
|
|
|
91
|
-
|
|
|
92
|
-
| `
|
|
93
|
-
| `
|
|
94
|
-
| `
|
|
95
|
-
| `
|
|
96
|
-
| `
|
|
93
|
+
| Property | Type | Default | Description |
|
|
94
|
+
| -------------------- | --------------- | --------------- | ------------------------------------------------------------------------------------------------- |
|
|
95
|
+
| `progress` | `number` | | Hardset the progress (0-100) if you want to bypass the internal store and control state yourself. |
|
|
96
|
+
| `color` | `string` | `"red"` | Background color of the bar. Accepts `linear-gradient(...)` or hex codes. |
|
|
97
|
+
| `height` | `number` | `2` | Height of the progress bar in pixels. |
|
|
98
|
+
| `shadow` | `boolean` | `true` | Appends a glorious trailing drop-glow peg matching the bar's color tracking its head. |
|
|
99
|
+
| `background` | `string` | `"transparent"` | Fills the container div's background layer under the progress element. |
|
|
100
|
+
| `transitionTime` | `number` | `300` | Fade transition time (ms) for the fade-out completion sequence. |
|
|
101
|
+
| `loaderSpeed` | `number` | `500` | Loader width transition speed (ms). |
|
|
102
|
+
| `waitingTime` | `number` | `1000` | The delay time (ms) loader waits at 100% width before fading entirely out. |
|
|
103
|
+
| `style` | `CSSProperties` | | Inject custom JSX styles directly onto the loader element. |
|
|
104
|
+
| `className` | `string` | | Apply a specific custom CSS class to the loader element. |
|
|
105
|
+
| `containerStyle` | `CSSProperties` | | Configure inline styles for the fixed `<div />` wrapper container. |
|
|
106
|
+
| `containerClassName` | `string` | | Custom CSS class applied onto the wrapper container. |
|
|
107
|
+
| `onLoaderFinished` | `() => void` | | A callback function executing precisely when the loader fully hits 100% max width. |
|
|
97
108
|
|
|
98
|
-
## Credits
|
|
109
|
+
## Credits
|
|
99
110
|
|
|
100
111
|
Designed for the modern web. Inspired by the classic `nprogress` and Next.js' `nextjs-toploader`. Ideal when you need explicit control without relying solely on framework routing events.
|
|
101
112
|
|
|
113
|
+
Built with ❤️ by **[Harry Mate](https://github.com/harrymate22)**.
|
|
114
|
+
🌟 If you find this library helpful, consider dropping a **Star** on GitHub and **[following me (@harrymate22)](https://github.com/harrymate22)** for more open-source tools!
|
|
115
|
+
|
|
102
116
|
## License
|
|
103
117
|
|
|
104
|
-
MIT
|
|
118
|
+
MIT © [harrymate22](https://github.com/harrymate22)
|
|
Binary file
|
package/dist/index.d.mts
CHANGED
|
@@ -1,16 +1,45 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React, { CSSProperties } from 'react';
|
|
2
2
|
|
|
3
3
|
interface TopProgressProps {
|
|
4
|
+
progress?: number;
|
|
4
5
|
color?: string;
|
|
6
|
+
shadow?: boolean;
|
|
5
7
|
height?: number;
|
|
8
|
+
background?: string;
|
|
9
|
+
style?: CSSProperties;
|
|
10
|
+
containerStyle?: CSSProperties;
|
|
11
|
+
shadowStyle?: CSSProperties;
|
|
12
|
+
transitionTime?: number;
|
|
13
|
+
loaderSpeed?: number;
|
|
14
|
+
waitingTime?: number;
|
|
15
|
+
className?: string;
|
|
16
|
+
containerClassName?: string;
|
|
17
|
+
onLoaderFinished?: () => void;
|
|
6
18
|
showGlow?: boolean;
|
|
7
19
|
glowColor?: string;
|
|
8
20
|
zIndex?: number;
|
|
9
21
|
}
|
|
10
|
-
|
|
22
|
+
interface TopProgressRef {
|
|
23
|
+
start: (loaderType?: "continuous" | "static") => void;
|
|
24
|
+
continuousStart: (startingValue?: number, refreshRate?: number) => void;
|
|
25
|
+
staticStart: (startingValue?: number) => void;
|
|
26
|
+
complete: () => void;
|
|
27
|
+
increase: (value: number) => void;
|
|
28
|
+
decrease: (value: number) => void;
|
|
29
|
+
getProgress: () => number | null;
|
|
30
|
+
set: (value: number) => void;
|
|
31
|
+
}
|
|
32
|
+
declare const TopProgress: React.ForwardRefExoticComponent<TopProgressProps & React.RefAttributes<TopProgressRef>>;
|
|
11
33
|
|
|
12
|
-
declare const startProgress: () => void;
|
|
34
|
+
declare const startProgress: (type?: "continuous" | "static") => void;
|
|
35
|
+
declare const continuousStart: (startingValue?: number, refreshRate?: number) => void;
|
|
36
|
+
declare const staticStart: (startingValue?: number) => void;
|
|
13
37
|
declare const finishProgress: () => void;
|
|
38
|
+
declare const completeProgress: () => void;
|
|
39
|
+
declare const increaseProgress: (value: number) => void;
|
|
40
|
+
declare const decreaseProgress: (value: number) => void;
|
|
41
|
+
declare const getProgress: () => number | null;
|
|
42
|
+
declare const setProgress: (value: number) => void;
|
|
14
43
|
declare const withProgress: <T>(promise: Promise<T>) => Promise<T>;
|
|
15
44
|
|
|
16
|
-
export { TopProgress, finishProgress, startProgress, withProgress };
|
|
45
|
+
export { TopProgress, type TopProgressProps, type TopProgressRef, completeProgress, continuousStart, decreaseProgress, finishProgress, getProgress, increaseProgress, setProgress, startProgress, staticStart, withProgress };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,16 +1,45 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React, { CSSProperties } from 'react';
|
|
2
2
|
|
|
3
3
|
interface TopProgressProps {
|
|
4
|
+
progress?: number;
|
|
4
5
|
color?: string;
|
|
6
|
+
shadow?: boolean;
|
|
5
7
|
height?: number;
|
|
8
|
+
background?: string;
|
|
9
|
+
style?: CSSProperties;
|
|
10
|
+
containerStyle?: CSSProperties;
|
|
11
|
+
shadowStyle?: CSSProperties;
|
|
12
|
+
transitionTime?: number;
|
|
13
|
+
loaderSpeed?: number;
|
|
14
|
+
waitingTime?: number;
|
|
15
|
+
className?: string;
|
|
16
|
+
containerClassName?: string;
|
|
17
|
+
onLoaderFinished?: () => void;
|
|
6
18
|
showGlow?: boolean;
|
|
7
19
|
glowColor?: string;
|
|
8
20
|
zIndex?: number;
|
|
9
21
|
}
|
|
10
|
-
|
|
22
|
+
interface TopProgressRef {
|
|
23
|
+
start: (loaderType?: "continuous" | "static") => void;
|
|
24
|
+
continuousStart: (startingValue?: number, refreshRate?: number) => void;
|
|
25
|
+
staticStart: (startingValue?: number) => void;
|
|
26
|
+
complete: () => void;
|
|
27
|
+
increase: (value: number) => void;
|
|
28
|
+
decrease: (value: number) => void;
|
|
29
|
+
getProgress: () => number | null;
|
|
30
|
+
set: (value: number) => void;
|
|
31
|
+
}
|
|
32
|
+
declare const TopProgress: React.ForwardRefExoticComponent<TopProgressProps & React.RefAttributes<TopProgressRef>>;
|
|
11
33
|
|
|
12
|
-
declare const startProgress: () => void;
|
|
34
|
+
declare const startProgress: (type?: "continuous" | "static") => void;
|
|
35
|
+
declare const continuousStart: (startingValue?: number, refreshRate?: number) => void;
|
|
36
|
+
declare const staticStart: (startingValue?: number) => void;
|
|
13
37
|
declare const finishProgress: () => void;
|
|
38
|
+
declare const completeProgress: () => void;
|
|
39
|
+
declare const increaseProgress: (value: number) => void;
|
|
40
|
+
declare const decreaseProgress: (value: number) => void;
|
|
41
|
+
declare const getProgress: () => number | null;
|
|
42
|
+
declare const setProgress: (value: number) => void;
|
|
14
43
|
declare const withProgress: <T>(promise: Promise<T>) => Promise<T>;
|
|
15
44
|
|
|
16
|
-
export { TopProgress, finishProgress, startProgress, withProgress };
|
|
45
|
+
export { TopProgress, type TopProgressProps, type TopProgressRef, completeProgress, continuousStart, decreaseProgress, finishProgress, getProgress, increaseProgress, setProgress, startProgress, staticStart, withProgress };
|
package/dist/index.js
CHANGED
|
@@ -22,8 +22,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
22
22
|
var index_exports = {};
|
|
23
23
|
__export(index_exports, {
|
|
24
24
|
TopProgress: () => TopProgress,
|
|
25
|
+
completeProgress: () => completeProgress,
|
|
26
|
+
continuousStart: () => continuousStart,
|
|
27
|
+
decreaseProgress: () => decreaseProgress,
|
|
25
28
|
finishProgress: () => finishProgress,
|
|
29
|
+
getProgress: () => getProgress,
|
|
30
|
+
increaseProgress: () => increaseProgress,
|
|
31
|
+
setProgress: () => setProgress,
|
|
26
32
|
startProgress: () => startProgress,
|
|
33
|
+
staticStart: () => staticStart,
|
|
27
34
|
withProgress: () => withProgress
|
|
28
35
|
});
|
|
29
36
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -37,6 +44,11 @@ var ProgressStore = class {
|
|
|
37
44
|
value = null;
|
|
38
45
|
interval = null;
|
|
39
46
|
hideTimer = null;
|
|
47
|
+
config = {
|
|
48
|
+
transitionTime: 300,
|
|
49
|
+
loaderSpeed: 500,
|
|
50
|
+
waitingTime: 1e3
|
|
51
|
+
};
|
|
40
52
|
subscribe(listener) {
|
|
41
53
|
this.listeners.add(listener);
|
|
42
54
|
listener(this.value);
|
|
@@ -47,27 +59,63 @@ var ProgressStore = class {
|
|
|
47
59
|
notify() {
|
|
48
60
|
this.listeners.forEach((listener) => listener(this.value));
|
|
49
61
|
}
|
|
50
|
-
start() {
|
|
51
|
-
if (
|
|
62
|
+
start(loaderType = "continuous") {
|
|
63
|
+
if (loaderType === "static") {
|
|
64
|
+
this.staticStart();
|
|
65
|
+
} else {
|
|
66
|
+
this.continuousStart();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
continuousStart(startingValue, refreshRate) {
|
|
52
70
|
this.cleanup();
|
|
53
|
-
this.value = 10;
|
|
71
|
+
this.value = startingValue !== void 0 ? startingValue : Math.floor(Math.random() * 10) + 20;
|
|
54
72
|
this.notify();
|
|
55
73
|
this.interval = setInterval(() => {
|
|
56
|
-
if (this.value !== null) {
|
|
57
|
-
const
|
|
58
|
-
this.value = Math.min(this.value +
|
|
74
|
+
if (this.value !== null && this.value < 90) {
|
|
75
|
+
const inc = Math.floor(Math.random() * 8) + 2;
|
|
76
|
+
this.value = Math.min(this.value + inc, 90);
|
|
59
77
|
this.notify();
|
|
60
78
|
}
|
|
61
|
-
},
|
|
79
|
+
}, refreshRate || this.config.loaderSpeed);
|
|
80
|
+
}
|
|
81
|
+
staticStart(startingValue) {
|
|
82
|
+
this.cleanup();
|
|
83
|
+
this.value = startingValue !== void 0 ? startingValue : Math.floor(Math.random() * 20) + 30;
|
|
84
|
+
this.notify();
|
|
85
|
+
}
|
|
86
|
+
complete() {
|
|
87
|
+
this.finish();
|
|
62
88
|
}
|
|
63
89
|
finish() {
|
|
64
90
|
this.cleanup();
|
|
91
|
+
if (this.value === null) return;
|
|
65
92
|
this.value = 100;
|
|
66
93
|
this.notify();
|
|
67
94
|
this.hideTimer = setTimeout(() => {
|
|
68
95
|
this.value = null;
|
|
69
96
|
this.notify();
|
|
70
|
-
},
|
|
97
|
+
}, this.config.waitingTime);
|
|
98
|
+
}
|
|
99
|
+
set(value) {
|
|
100
|
+
this.cleanup();
|
|
101
|
+
this.value = value;
|
|
102
|
+
this.notify();
|
|
103
|
+
if (value >= 100) {
|
|
104
|
+
this.finish();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
increase(amount) {
|
|
108
|
+
if (this.value !== null) {
|
|
109
|
+
this.value = Math.min(this.value + amount, 100);
|
|
110
|
+
this.notify();
|
|
111
|
+
if (this.value === 100) this.finish();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
decrease(amount) {
|
|
115
|
+
if (this.value !== null) {
|
|
116
|
+
this.value = Math.max(0, this.value - amount);
|
|
117
|
+
this.notify();
|
|
118
|
+
}
|
|
71
119
|
}
|
|
72
120
|
cleanup() {
|
|
73
121
|
if (this.interval) clearInterval(this.interval);
|
|
@@ -76,11 +124,21 @@ var ProgressStore = class {
|
|
|
76
124
|
getValue() {
|
|
77
125
|
return this.value;
|
|
78
126
|
}
|
|
127
|
+
getProgress() {
|
|
128
|
+
return this.value;
|
|
129
|
+
}
|
|
79
130
|
};
|
|
80
131
|
var progressStore = new ProgressStore();
|
|
81
132
|
var useProgressStore = () => progressStore;
|
|
82
|
-
var startProgress = () => progressStore.start();
|
|
133
|
+
var startProgress = (type) => progressStore.start(type);
|
|
134
|
+
var continuousStart = (startingValue, refreshRate) => progressStore.continuousStart(startingValue, refreshRate);
|
|
135
|
+
var staticStart = (startingValue) => progressStore.staticStart(startingValue);
|
|
83
136
|
var finishProgress = () => progressStore.finish();
|
|
137
|
+
var completeProgress = () => progressStore.complete();
|
|
138
|
+
var increaseProgress = (value) => progressStore.increase(value);
|
|
139
|
+
var decreaseProgress = (value) => progressStore.decrease(value);
|
|
140
|
+
var getProgress = () => progressStore.getProgress();
|
|
141
|
+
var setProgress = (value) => progressStore.set(value);
|
|
84
142
|
var withProgress = async (promise) => {
|
|
85
143
|
startProgress();
|
|
86
144
|
try {
|
|
@@ -95,69 +153,124 @@ var withProgress = async (promise) => {
|
|
|
95
153
|
|
|
96
154
|
// src/TopProgress.tsx
|
|
97
155
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
98
|
-
var TopProgress = (
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
boxShadow: `0 0 10px ${computedGlowColor}, 0 0 5px ${computedGlowColor}`,
|
|
149
|
-
opacity: 1,
|
|
150
|
-
transform: "rotate(3deg) translate(0px, -4px)"
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
)
|
|
156
|
+
var TopProgress = (0, import_react.forwardRef)(
|
|
157
|
+
({
|
|
158
|
+
progress: controlledProgress,
|
|
159
|
+
color = "red",
|
|
160
|
+
shadow = true,
|
|
161
|
+
height = 2,
|
|
162
|
+
background = "transparent",
|
|
163
|
+
style,
|
|
164
|
+
containerStyle,
|
|
165
|
+
shadowStyle,
|
|
166
|
+
transitionTime = 300,
|
|
167
|
+
loaderSpeed = 500,
|
|
168
|
+
waitingTime = 1e3,
|
|
169
|
+
className,
|
|
170
|
+
containerClassName,
|
|
171
|
+
onLoaderFinished,
|
|
172
|
+
showGlow,
|
|
173
|
+
glowColor,
|
|
174
|
+
zIndex = 9999
|
|
175
|
+
}, ref) => {
|
|
176
|
+
const store = useProgressStore();
|
|
177
|
+
const [internalProgress, setInternalProgress] = (0, import_react.useState)(
|
|
178
|
+
store.getValue()
|
|
179
|
+
);
|
|
180
|
+
(0, import_react.useImperativeHandle)(ref, () => ({
|
|
181
|
+
start: (type) => store.start(type),
|
|
182
|
+
continuousStart: (s, r) => store.continuousStart(s, r),
|
|
183
|
+
staticStart: (s) => store.staticStart(s),
|
|
184
|
+
complete: () => store.complete(),
|
|
185
|
+
increase: (v) => store.increase(v),
|
|
186
|
+
decrease: (v) => store.decrease(v),
|
|
187
|
+
getProgress: () => store.getProgress(),
|
|
188
|
+
set: (v) => store.set(v)
|
|
189
|
+
}));
|
|
190
|
+
(0, import_react.useEffect)(() => {
|
|
191
|
+
store.config.transitionTime = transitionTime;
|
|
192
|
+
store.config.loaderSpeed = loaderSpeed;
|
|
193
|
+
store.config.waitingTime = waitingTime;
|
|
194
|
+
}, [transitionTime, loaderSpeed, waitingTime, store]);
|
|
195
|
+
(0, import_react.useEffect)(() => {
|
|
196
|
+
return store.subscribe(setInternalProgress);
|
|
197
|
+
}, [store]);
|
|
198
|
+
const progress = controlledProgress !== void 0 ? controlledProgress : internalProgress;
|
|
199
|
+
(0, import_react.useEffect)(() => {
|
|
200
|
+
if (progress === 100 && onLoaderFinished) {
|
|
201
|
+
onLoaderFinished();
|
|
202
|
+
}
|
|
203
|
+
}, [progress, onLoaderFinished]);
|
|
204
|
+
if (progress === null) {
|
|
205
|
+
return null;
|
|
154
206
|
}
|
|
155
|
-
|
|
156
|
-
};
|
|
207
|
+
const isGradient = color.includes("gradient(");
|
|
208
|
+
const backgroundStyle = isGradient ? { backgroundImage: color } : { backgroundColor: color };
|
|
209
|
+
const useShadow = showGlow !== void 0 ? showGlow : shadow;
|
|
210
|
+
const computedGlowColor = glowColor || (isGradient ? "rgba(41, 216, 255, 0.4)" : color);
|
|
211
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
212
|
+
"div",
|
|
213
|
+
{
|
|
214
|
+
className: containerClassName,
|
|
215
|
+
style: {
|
|
216
|
+
position: "fixed",
|
|
217
|
+
top: 0,
|
|
218
|
+
left: 0,
|
|
219
|
+
width: "100%",
|
|
220
|
+
height: `${height}px`,
|
|
221
|
+
backgroundColor: background,
|
|
222
|
+
zIndex,
|
|
223
|
+
pointerEvents: "none",
|
|
224
|
+
...containerStyle
|
|
225
|
+
},
|
|
226
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
227
|
+
"div",
|
|
228
|
+
{
|
|
229
|
+
className,
|
|
230
|
+
style: {
|
|
231
|
+
width: `${progress}%`,
|
|
232
|
+
height: "100%",
|
|
233
|
+
...backgroundStyle,
|
|
234
|
+
transition: `width ${loaderSpeed}ms cubic-bezier(0.4, 0, 0.2, 1), opacity ${transitionTime}ms ease`,
|
|
235
|
+
opacity: progress === 100 ? 0 : 1,
|
|
236
|
+
transform: "translateZ(0)",
|
|
237
|
+
...style
|
|
238
|
+
},
|
|
239
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
240
|
+
"div",
|
|
241
|
+
{
|
|
242
|
+
style: {
|
|
243
|
+
display: useShadow ? "block" : "none",
|
|
244
|
+
position: "absolute",
|
|
245
|
+
right: 0,
|
|
246
|
+
top: 0,
|
|
247
|
+
width: 100,
|
|
248
|
+
height: "100%",
|
|
249
|
+
boxShadow: `0 0 10px ${computedGlowColor}, 0 0 5px ${computedGlowColor}`,
|
|
250
|
+
opacity: 1,
|
|
251
|
+
transform: "rotate(3deg) translate(0px, -4px)",
|
|
252
|
+
...shadowStyle
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
)
|
|
256
|
+
}
|
|
257
|
+
)
|
|
258
|
+
}
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
);
|
|
262
|
+
TopProgress.displayName = "TopProgress";
|
|
157
263
|
// Annotate the CommonJS export names for ESM import in node:
|
|
158
264
|
0 && (module.exports = {
|
|
159
265
|
TopProgress,
|
|
266
|
+
completeProgress,
|
|
267
|
+
continuousStart,
|
|
268
|
+
decreaseProgress,
|
|
160
269
|
finishProgress,
|
|
270
|
+
getProgress,
|
|
271
|
+
increaseProgress,
|
|
272
|
+
setProgress,
|
|
161
273
|
startProgress,
|
|
274
|
+
staticStart,
|
|
162
275
|
withProgress
|
|
163
276
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/TopProgress.tsx
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
useEffect,
|
|
6
|
+
useState,
|
|
7
|
+
forwardRef,
|
|
8
|
+
useImperativeHandle
|
|
9
|
+
} from "react";
|
|
5
10
|
|
|
6
11
|
// src/progressStore.ts
|
|
7
12
|
var ProgressStore = class {
|
|
@@ -9,6 +14,11 @@ var ProgressStore = class {
|
|
|
9
14
|
value = null;
|
|
10
15
|
interval = null;
|
|
11
16
|
hideTimer = null;
|
|
17
|
+
config = {
|
|
18
|
+
transitionTime: 300,
|
|
19
|
+
loaderSpeed: 500,
|
|
20
|
+
waitingTime: 1e3
|
|
21
|
+
};
|
|
12
22
|
subscribe(listener) {
|
|
13
23
|
this.listeners.add(listener);
|
|
14
24
|
listener(this.value);
|
|
@@ -19,27 +29,63 @@ var ProgressStore = class {
|
|
|
19
29
|
notify() {
|
|
20
30
|
this.listeners.forEach((listener) => listener(this.value));
|
|
21
31
|
}
|
|
22
|
-
start() {
|
|
23
|
-
if (
|
|
32
|
+
start(loaderType = "continuous") {
|
|
33
|
+
if (loaderType === "static") {
|
|
34
|
+
this.staticStart();
|
|
35
|
+
} else {
|
|
36
|
+
this.continuousStart();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
continuousStart(startingValue, refreshRate) {
|
|
24
40
|
this.cleanup();
|
|
25
|
-
this.value = 10;
|
|
41
|
+
this.value = startingValue !== void 0 ? startingValue : Math.floor(Math.random() * 10) + 20;
|
|
26
42
|
this.notify();
|
|
27
43
|
this.interval = setInterval(() => {
|
|
28
|
-
if (this.value !== null) {
|
|
29
|
-
const
|
|
30
|
-
this.value = Math.min(this.value +
|
|
44
|
+
if (this.value !== null && this.value < 90) {
|
|
45
|
+
const inc = Math.floor(Math.random() * 8) + 2;
|
|
46
|
+
this.value = Math.min(this.value + inc, 90);
|
|
31
47
|
this.notify();
|
|
32
48
|
}
|
|
33
|
-
},
|
|
49
|
+
}, refreshRate || this.config.loaderSpeed);
|
|
50
|
+
}
|
|
51
|
+
staticStart(startingValue) {
|
|
52
|
+
this.cleanup();
|
|
53
|
+
this.value = startingValue !== void 0 ? startingValue : Math.floor(Math.random() * 20) + 30;
|
|
54
|
+
this.notify();
|
|
55
|
+
}
|
|
56
|
+
complete() {
|
|
57
|
+
this.finish();
|
|
34
58
|
}
|
|
35
59
|
finish() {
|
|
36
60
|
this.cleanup();
|
|
61
|
+
if (this.value === null) return;
|
|
37
62
|
this.value = 100;
|
|
38
63
|
this.notify();
|
|
39
64
|
this.hideTimer = setTimeout(() => {
|
|
40
65
|
this.value = null;
|
|
41
66
|
this.notify();
|
|
42
|
-
},
|
|
67
|
+
}, this.config.waitingTime);
|
|
68
|
+
}
|
|
69
|
+
set(value) {
|
|
70
|
+
this.cleanup();
|
|
71
|
+
this.value = value;
|
|
72
|
+
this.notify();
|
|
73
|
+
if (value >= 100) {
|
|
74
|
+
this.finish();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
increase(amount) {
|
|
78
|
+
if (this.value !== null) {
|
|
79
|
+
this.value = Math.min(this.value + amount, 100);
|
|
80
|
+
this.notify();
|
|
81
|
+
if (this.value === 100) this.finish();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
decrease(amount) {
|
|
85
|
+
if (this.value !== null) {
|
|
86
|
+
this.value = Math.max(0, this.value - amount);
|
|
87
|
+
this.notify();
|
|
88
|
+
}
|
|
43
89
|
}
|
|
44
90
|
cleanup() {
|
|
45
91
|
if (this.interval) clearInterval(this.interval);
|
|
@@ -48,11 +94,21 @@ var ProgressStore = class {
|
|
|
48
94
|
getValue() {
|
|
49
95
|
return this.value;
|
|
50
96
|
}
|
|
97
|
+
getProgress() {
|
|
98
|
+
return this.value;
|
|
99
|
+
}
|
|
51
100
|
};
|
|
52
101
|
var progressStore = new ProgressStore();
|
|
53
102
|
var useProgressStore = () => progressStore;
|
|
54
|
-
var startProgress = () => progressStore.start();
|
|
103
|
+
var startProgress = (type) => progressStore.start(type);
|
|
104
|
+
var continuousStart = (startingValue, refreshRate) => progressStore.continuousStart(startingValue, refreshRate);
|
|
105
|
+
var staticStart = (startingValue) => progressStore.staticStart(startingValue);
|
|
55
106
|
var finishProgress = () => progressStore.finish();
|
|
107
|
+
var completeProgress = () => progressStore.complete();
|
|
108
|
+
var increaseProgress = (value) => progressStore.increase(value);
|
|
109
|
+
var decreaseProgress = (value) => progressStore.decrease(value);
|
|
110
|
+
var getProgress = () => progressStore.getProgress();
|
|
111
|
+
var setProgress = (value) => progressStore.set(value);
|
|
56
112
|
var withProgress = async (promise) => {
|
|
57
113
|
startProgress();
|
|
58
114
|
try {
|
|
@@ -67,68 +123,123 @@ var withProgress = async (promise) => {
|
|
|
67
123
|
|
|
68
124
|
// src/TopProgress.tsx
|
|
69
125
|
import { jsx } from "react/jsx-runtime";
|
|
70
|
-
var TopProgress = (
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
boxShadow: `0 0 10px ${computedGlowColor}, 0 0 5px ${computedGlowColor}`,
|
|
121
|
-
opacity: 1,
|
|
122
|
-
transform: "rotate(3deg) translate(0px, -4px)"
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
)
|
|
126
|
+
var TopProgress = forwardRef(
|
|
127
|
+
({
|
|
128
|
+
progress: controlledProgress,
|
|
129
|
+
color = "red",
|
|
130
|
+
shadow = true,
|
|
131
|
+
height = 2,
|
|
132
|
+
background = "transparent",
|
|
133
|
+
style,
|
|
134
|
+
containerStyle,
|
|
135
|
+
shadowStyle,
|
|
136
|
+
transitionTime = 300,
|
|
137
|
+
loaderSpeed = 500,
|
|
138
|
+
waitingTime = 1e3,
|
|
139
|
+
className,
|
|
140
|
+
containerClassName,
|
|
141
|
+
onLoaderFinished,
|
|
142
|
+
showGlow,
|
|
143
|
+
glowColor,
|
|
144
|
+
zIndex = 9999
|
|
145
|
+
}, ref) => {
|
|
146
|
+
const store = useProgressStore();
|
|
147
|
+
const [internalProgress, setInternalProgress] = useState(
|
|
148
|
+
store.getValue()
|
|
149
|
+
);
|
|
150
|
+
useImperativeHandle(ref, () => ({
|
|
151
|
+
start: (type) => store.start(type),
|
|
152
|
+
continuousStart: (s, r) => store.continuousStart(s, r),
|
|
153
|
+
staticStart: (s) => store.staticStart(s),
|
|
154
|
+
complete: () => store.complete(),
|
|
155
|
+
increase: (v) => store.increase(v),
|
|
156
|
+
decrease: (v) => store.decrease(v),
|
|
157
|
+
getProgress: () => store.getProgress(),
|
|
158
|
+
set: (v) => store.set(v)
|
|
159
|
+
}));
|
|
160
|
+
useEffect(() => {
|
|
161
|
+
store.config.transitionTime = transitionTime;
|
|
162
|
+
store.config.loaderSpeed = loaderSpeed;
|
|
163
|
+
store.config.waitingTime = waitingTime;
|
|
164
|
+
}, [transitionTime, loaderSpeed, waitingTime, store]);
|
|
165
|
+
useEffect(() => {
|
|
166
|
+
return store.subscribe(setInternalProgress);
|
|
167
|
+
}, [store]);
|
|
168
|
+
const progress = controlledProgress !== void 0 ? controlledProgress : internalProgress;
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
if (progress === 100 && onLoaderFinished) {
|
|
171
|
+
onLoaderFinished();
|
|
172
|
+
}
|
|
173
|
+
}, [progress, onLoaderFinished]);
|
|
174
|
+
if (progress === null) {
|
|
175
|
+
return null;
|
|
126
176
|
}
|
|
127
|
-
|
|
128
|
-
};
|
|
177
|
+
const isGradient = color.includes("gradient(");
|
|
178
|
+
const backgroundStyle = isGradient ? { backgroundImage: color } : { backgroundColor: color };
|
|
179
|
+
const useShadow = showGlow !== void 0 ? showGlow : shadow;
|
|
180
|
+
const computedGlowColor = glowColor || (isGradient ? "rgba(41, 216, 255, 0.4)" : color);
|
|
181
|
+
return /* @__PURE__ */ jsx(
|
|
182
|
+
"div",
|
|
183
|
+
{
|
|
184
|
+
className: containerClassName,
|
|
185
|
+
style: {
|
|
186
|
+
position: "fixed",
|
|
187
|
+
top: 0,
|
|
188
|
+
left: 0,
|
|
189
|
+
width: "100%",
|
|
190
|
+
height: `${height}px`,
|
|
191
|
+
backgroundColor: background,
|
|
192
|
+
zIndex,
|
|
193
|
+
pointerEvents: "none",
|
|
194
|
+
...containerStyle
|
|
195
|
+
},
|
|
196
|
+
children: /* @__PURE__ */ jsx(
|
|
197
|
+
"div",
|
|
198
|
+
{
|
|
199
|
+
className,
|
|
200
|
+
style: {
|
|
201
|
+
width: `${progress}%`,
|
|
202
|
+
height: "100%",
|
|
203
|
+
...backgroundStyle,
|
|
204
|
+
transition: `width ${loaderSpeed}ms cubic-bezier(0.4, 0, 0.2, 1), opacity ${transitionTime}ms ease`,
|
|
205
|
+
opacity: progress === 100 ? 0 : 1,
|
|
206
|
+
transform: "translateZ(0)",
|
|
207
|
+
...style
|
|
208
|
+
},
|
|
209
|
+
children: /* @__PURE__ */ jsx(
|
|
210
|
+
"div",
|
|
211
|
+
{
|
|
212
|
+
style: {
|
|
213
|
+
display: useShadow ? "block" : "none",
|
|
214
|
+
position: "absolute",
|
|
215
|
+
right: 0,
|
|
216
|
+
top: 0,
|
|
217
|
+
width: 100,
|
|
218
|
+
height: "100%",
|
|
219
|
+
boxShadow: `0 0 10px ${computedGlowColor}, 0 0 5px ${computedGlowColor}`,
|
|
220
|
+
opacity: 1,
|
|
221
|
+
transform: "rotate(3deg) translate(0px, -4px)",
|
|
222
|
+
...shadowStyle
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
)
|
|
226
|
+
}
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
);
|
|
232
|
+
TopProgress.displayName = "TopProgress";
|
|
129
233
|
export {
|
|
130
234
|
TopProgress,
|
|
235
|
+
completeProgress,
|
|
236
|
+
continuousStart,
|
|
237
|
+
decreaseProgress,
|
|
131
238
|
finishProgress,
|
|
239
|
+
getProgress,
|
|
240
|
+
increaseProgress,
|
|
241
|
+
setProgress,
|
|
132
242
|
startProgress,
|
|
243
|
+
staticStart,
|
|
133
244
|
withProgress
|
|
134
245
|
};
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-top-progress",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "A lightweight modern top loading progress bar for React",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"files": [
|
|
9
9
|
"dist",
|
|
10
|
-
"demo_react_top_progress.
|
|
10
|
+
"demo_react_top_progress.webp"
|
|
11
11
|
],
|
|
12
12
|
"keywords": [
|
|
13
13
|
"react",
|
|
Binary file
|