react-top-progress
Advanced tools
Sorry, the diff of this file is not supported yet
+33
-4
@@ -1,6 +0,18 @@ | ||
| import * as react_jsx_runtime from 'react/jsx-runtime'; | ||
| import React, { CSSProperties } from 'react'; | ||
| interface TopProgressProps { | ||
| progress?: number; | ||
| color?: string; | ||
| shadow?: boolean; | ||
| height?: number; | ||
| background?: string; | ||
| style?: CSSProperties; | ||
| containerStyle?: CSSProperties; | ||
| shadowStyle?: CSSProperties; | ||
| transitionTime?: number; | ||
| loaderSpeed?: number; | ||
| waitingTime?: number; | ||
| className?: string; | ||
| containerClassName?: string; | ||
| onLoaderFinished?: () => void; | ||
| showGlow?: boolean; | ||
@@ -10,8 +22,25 @@ glowColor?: string; | ||
| } | ||
| declare const TopProgress: ({ color, height, showGlow, glowColor, zIndex, }: TopProgressProps) => react_jsx_runtime.JSX.Element | null; | ||
| interface TopProgressRef { | ||
| start: (loaderType?: "continuous" | "static") => void; | ||
| continuousStart: (startingValue?: number, refreshRate?: number) => void; | ||
| staticStart: (startingValue?: number) => void; | ||
| complete: () => void; | ||
| increase: (value: number) => void; | ||
| decrease: (value: number) => void; | ||
| getProgress: () => number | null; | ||
| set: (value: number) => void; | ||
| } | ||
| declare const TopProgress: React.ForwardRefExoticComponent<TopProgressProps & React.RefAttributes<TopProgressRef>>; | ||
| declare const startProgress: () => void; | ||
| declare const startProgress: (type?: "continuous" | "static") => void; | ||
| declare const continuousStart: (startingValue?: number, refreshRate?: number) => void; | ||
| declare const staticStart: (startingValue?: number) => void; | ||
| declare const finishProgress: () => void; | ||
| declare const completeProgress: () => void; | ||
| declare const increaseProgress: (value: number) => void; | ||
| declare const decreaseProgress: (value: number) => void; | ||
| declare const getProgress: () => number | null; | ||
| declare const setProgress: (value: number) => void; | ||
| declare const withProgress: <T>(promise: Promise<T>) => Promise<T>; | ||
| export { TopProgress, finishProgress, startProgress, withProgress }; | ||
| export { TopProgress, type TopProgressProps, type TopProgressRef, completeProgress, continuousStart, decreaseProgress, finishProgress, getProgress, increaseProgress, setProgress, startProgress, staticStart, withProgress }; |
+33
-4
@@ -1,6 +0,18 @@ | ||
| import * as react_jsx_runtime from 'react/jsx-runtime'; | ||
| import React, { CSSProperties } from 'react'; | ||
| interface TopProgressProps { | ||
| progress?: number; | ||
| color?: string; | ||
| shadow?: boolean; | ||
| height?: number; | ||
| background?: string; | ||
| style?: CSSProperties; | ||
| containerStyle?: CSSProperties; | ||
| shadowStyle?: CSSProperties; | ||
| transitionTime?: number; | ||
| loaderSpeed?: number; | ||
| waitingTime?: number; | ||
| className?: string; | ||
| containerClassName?: string; | ||
| onLoaderFinished?: () => void; | ||
| showGlow?: boolean; | ||
@@ -10,8 +22,25 @@ glowColor?: string; | ||
| } | ||
| declare const TopProgress: ({ color, height, showGlow, glowColor, zIndex, }: TopProgressProps) => react_jsx_runtime.JSX.Element | null; | ||
| interface TopProgressRef { | ||
| start: (loaderType?: "continuous" | "static") => void; | ||
| continuousStart: (startingValue?: number, refreshRate?: number) => void; | ||
| staticStart: (startingValue?: number) => void; | ||
| complete: () => void; | ||
| increase: (value: number) => void; | ||
| decrease: (value: number) => void; | ||
| getProgress: () => number | null; | ||
| set: (value: number) => void; | ||
| } | ||
| declare const TopProgress: React.ForwardRefExoticComponent<TopProgressProps & React.RefAttributes<TopProgressRef>>; | ||
| declare const startProgress: () => void; | ||
| declare const startProgress: (type?: "continuous" | "static") => void; | ||
| declare const continuousStart: (startingValue?: number, refreshRate?: number) => void; | ||
| declare const staticStart: (startingValue?: number) => void; | ||
| declare const finishProgress: () => void; | ||
| declare const completeProgress: () => void; | ||
| declare const increaseProgress: (value: number) => void; | ||
| declare const decreaseProgress: (value: number) => void; | ||
| declare const getProgress: () => number | null; | ||
| declare const setProgress: (value: number) => void; | ||
| declare const withProgress: <T>(promise: Promise<T>) => Promise<T>; | ||
| export { TopProgress, finishProgress, startProgress, withProgress }; | ||
| export { TopProgress, type TopProgressProps, type TopProgressRef, completeProgress, continuousStart, decreaseProgress, finishProgress, getProgress, increaseProgress, setProgress, startProgress, staticStart, withProgress }; |
+180
-67
@@ -25,4 +25,11 @@ "use strict"; | ||
| TopProgress: () => TopProgress, | ||
| completeProgress: () => completeProgress, | ||
| continuousStart: () => continuousStart, | ||
| decreaseProgress: () => decreaseProgress, | ||
| finishProgress: () => finishProgress, | ||
| getProgress: () => getProgress, | ||
| increaseProgress: () => increaseProgress, | ||
| setProgress: () => setProgress, | ||
| startProgress: () => startProgress, | ||
| staticStart: () => staticStart, | ||
| withProgress: () => withProgress | ||
@@ -41,2 +48,7 @@ }); | ||
| hideTimer = null; | ||
| config = { | ||
| transitionTime: 300, | ||
| loaderSpeed: 500, | ||
| waitingTime: 1e3 | ||
| }; | ||
| subscribe(listener) { | ||
@@ -52,17 +64,32 @@ this.listeners.add(listener); | ||
| } | ||
| start() { | ||
| if (this.value !== null) return; | ||
| start(loaderType = "continuous") { | ||
| if (loaderType === "static") { | ||
| this.staticStart(); | ||
| } else { | ||
| this.continuousStart(); | ||
| } | ||
| } | ||
| continuousStart(startingValue, refreshRate) { | ||
| this.cleanup(); | ||
| this.value = 10; | ||
| this.value = startingValue !== void 0 ? startingValue : Math.floor(Math.random() * 10) + 20; | ||
| this.notify(); | ||
| this.interval = setInterval(() => { | ||
| if (this.value !== null) { | ||
| const amount = Math.max(0.5, (95 - this.value) / 10); | ||
| this.value = Math.min(this.value + amount, 95); | ||
| if (this.value !== null && this.value < 90) { | ||
| const inc = Math.floor(Math.random() * 8) + 2; | ||
| this.value = Math.min(this.value + inc, 90); | ||
| this.notify(); | ||
| } | ||
| }, 200); | ||
| }, refreshRate || this.config.loaderSpeed); | ||
| } | ||
| staticStart(startingValue) { | ||
| this.cleanup(); | ||
| this.value = startingValue !== void 0 ? startingValue : Math.floor(Math.random() * 20) + 30; | ||
| this.notify(); | ||
| } | ||
| complete() { | ||
| this.finish(); | ||
| } | ||
| finish() { | ||
| this.cleanup(); | ||
| if (this.value === null) return; | ||
| this.value = 100; | ||
@@ -73,4 +100,25 @@ this.notify(); | ||
| this.notify(); | ||
| }, 400); | ||
| }, this.config.waitingTime); | ||
| } | ||
| set(value) { | ||
| this.cleanup(); | ||
| this.value = value; | ||
| this.notify(); | ||
| if (value >= 100) { | ||
| this.finish(); | ||
| } | ||
| } | ||
| increase(amount) { | ||
| if (this.value !== null) { | ||
| this.value = Math.min(this.value + amount, 100); | ||
| this.notify(); | ||
| if (this.value === 100) this.finish(); | ||
| } | ||
| } | ||
| decrease(amount) { | ||
| if (this.value !== null) { | ||
| this.value = Math.max(0, this.value - amount); | ||
| this.notify(); | ||
| } | ||
| } | ||
| cleanup() { | ||
@@ -83,7 +131,17 @@ if (this.interval) clearInterval(this.interval); | ||
| } | ||
| getProgress() { | ||
| return this.value; | ||
| } | ||
| }; | ||
| var progressStore = new ProgressStore(); | ||
| var useProgressStore = () => progressStore; | ||
| var startProgress = () => progressStore.start(); | ||
| var startProgress = (type) => progressStore.start(type); | ||
| var continuousStart = (startingValue, refreshRate) => progressStore.continuousStart(startingValue, refreshRate); | ||
| var staticStart = (startingValue) => progressStore.staticStart(startingValue); | ||
| var finishProgress = () => progressStore.finish(); | ||
| var completeProgress = () => progressStore.complete(); | ||
| var increaseProgress = (value) => progressStore.increase(value); | ||
| var decreaseProgress = (value) => progressStore.decrease(value); | ||
| var getProgress = () => progressStore.getProgress(); | ||
| var setProgress = (value) => progressStore.set(value); | ||
| var withProgress = async (promise) => { | ||
@@ -103,67 +161,122 @@ startProgress(); | ||
| var import_jsx_runtime = require("react/jsx-runtime"); | ||
| var TopProgress = ({ | ||
| color = "#29D", | ||
| // Still the default flat color, but can now accept "linear-gradient(...)" | ||
| height = 3, | ||
| showGlow = true, | ||
| glowColor, | ||
| zIndex = 9999 | ||
| }) => { | ||
| const store = useProgressStore(); | ||
| const [progress, setProgress] = (0, import_react.useState)(store.getValue()); | ||
| (0, import_react.useEffect)(() => { | ||
| return store.subscribe(setProgress); | ||
| }, [store]); | ||
| if (progress === null) { | ||
| return null; | ||
| var TopProgress = (0, import_react.forwardRef)( | ||
| ({ | ||
| progress: controlledProgress, | ||
| color = "red", | ||
| shadow = true, | ||
| height = 2, | ||
| background = "transparent", | ||
| style, | ||
| containerStyle, | ||
| shadowStyle, | ||
| transitionTime = 300, | ||
| loaderSpeed = 500, | ||
| waitingTime = 1e3, | ||
| className, | ||
| containerClassName, | ||
| onLoaderFinished, | ||
| showGlow, | ||
| glowColor, | ||
| zIndex = 9999 | ||
| }, ref) => { | ||
| const store = useProgressStore(); | ||
| const [internalProgress, setInternalProgress] = (0, import_react.useState)( | ||
| store.getValue() | ||
| ); | ||
| (0, import_react.useImperativeHandle)(ref, () => ({ | ||
| start: (type) => store.start(type), | ||
| continuousStart: (s, r) => store.continuousStart(s, r), | ||
| staticStart: (s) => store.staticStart(s), | ||
| complete: () => store.complete(), | ||
| increase: (v) => store.increase(v), | ||
| decrease: (v) => store.decrease(v), | ||
| getProgress: () => store.getProgress(), | ||
| set: (v) => store.set(v) | ||
| })); | ||
| (0, import_react.useEffect)(() => { | ||
| store.config.transitionTime = transitionTime; | ||
| store.config.loaderSpeed = loaderSpeed; | ||
| store.config.waitingTime = waitingTime; | ||
| }, [transitionTime, loaderSpeed, waitingTime, store]); | ||
| (0, import_react.useEffect)(() => { | ||
| return store.subscribe(setInternalProgress); | ||
| }, [store]); | ||
| const progress = controlledProgress !== void 0 ? controlledProgress : internalProgress; | ||
| (0, import_react.useEffect)(() => { | ||
| if (progress === 100 && onLoaderFinished) { | ||
| onLoaderFinished(); | ||
| } | ||
| }, [progress, onLoaderFinished]); | ||
| if (progress === null) { | ||
| return null; | ||
| } | ||
| const isGradient = color.includes("gradient("); | ||
| const backgroundStyle = isGradient ? { backgroundImage: color } : { backgroundColor: color }; | ||
| const useShadow = showGlow !== void 0 ? showGlow : shadow; | ||
| const computedGlowColor = glowColor || (isGradient ? "rgba(41, 216, 255, 0.4)" : color); | ||
| return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
| "div", | ||
| { | ||
| className: containerClassName, | ||
| style: { | ||
| position: "fixed", | ||
| top: 0, | ||
| left: 0, | ||
| width: "100%", | ||
| height: `${height}px`, | ||
| backgroundColor: background, | ||
| zIndex, | ||
| pointerEvents: "none", | ||
| ...containerStyle | ||
| }, | ||
| children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
| "div", | ||
| { | ||
| className, | ||
| style: { | ||
| width: `${progress}%`, | ||
| height: "100%", | ||
| ...backgroundStyle, | ||
| transition: `width ${loaderSpeed}ms cubic-bezier(0.4, 0, 0.2, 1), opacity ${transitionTime}ms ease`, | ||
| opacity: progress === 100 ? 0 : 1, | ||
| transform: "translateZ(0)", | ||
| ...style | ||
| }, | ||
| children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
| "div", | ||
| { | ||
| style: { | ||
| display: useShadow ? "block" : "none", | ||
| position: "absolute", | ||
| right: 0, | ||
| top: 0, | ||
| width: 100, | ||
| height: "100%", | ||
| boxShadow: `0 0 10px ${computedGlowColor}, 0 0 5px ${computedGlowColor}`, | ||
| opacity: 1, | ||
| transform: "rotate(3deg) translate(0px, -4px)", | ||
| ...shadowStyle | ||
| } | ||
| } | ||
| ) | ||
| } | ||
| ) | ||
| } | ||
| ); | ||
| } | ||
| const isGradient = color.includes("gradient("); | ||
| const backgroundStyle = isGradient ? { backgroundImage: color } : { backgroundColor: color }; | ||
| const computedGlowColor = glowColor || (isGradient ? "rgba(41, 216, 255, 0.4)" : color); | ||
| return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
| "div", | ||
| { | ||
| style: { | ||
| position: "fixed", | ||
| top: 0, | ||
| left: 0, | ||
| width: `${progress}%`, | ||
| height: `${height}px`, | ||
| ...backgroundStyle, | ||
| // Box shadow generates a beautiful diffused glow underneath the progress bar | ||
| boxShadow: showGlow ? `0 0 10px ${computedGlowColor}, 0 0 5px ${computedGlowColor}` : "none", | ||
| // Smooth and performant 60fps CSS transitions | ||
| transition: "width 0.2s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.4s ease", | ||
| opacity: progress === 100 ? 0 : 1, | ||
| zIndex, | ||
| // Force hardware acceleration for paint performance | ||
| transform: "translateZ(0)", | ||
| // Don't intercept clicks | ||
| pointerEvents: "none" | ||
| }, | ||
| children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | ||
| "div", | ||
| { | ||
| style: { | ||
| display: showGlow ? "block" : "none", | ||
| position: "absolute", | ||
| right: 0, | ||
| top: 0, | ||
| width: 100, | ||
| height: "100%", | ||
| boxShadow: `0 0 10px ${computedGlowColor}, 0 0 5px ${computedGlowColor}`, | ||
| opacity: 1, | ||
| transform: "rotate(3deg) translate(0px, -4px)" | ||
| } | ||
| } | ||
| ) | ||
| } | ||
| ); | ||
| }; | ||
| ); | ||
| TopProgress.displayName = "TopProgress"; | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| TopProgress, | ||
| completeProgress, | ||
| continuousStart, | ||
| decreaseProgress, | ||
| finishProgress, | ||
| getProgress, | ||
| increaseProgress, | ||
| setProgress, | ||
| startProgress, | ||
| staticStart, | ||
| withProgress | ||
| }); |
+179
-68
| "use client"; | ||
| // src/TopProgress.tsx | ||
| import { useEffect, useState } from "react"; | ||
| import { | ||
| useEffect, | ||
| useState, | ||
| forwardRef, | ||
| useImperativeHandle | ||
| } from "react"; | ||
@@ -12,2 +17,7 @@ // src/progressStore.ts | ||
| hideTimer = null; | ||
| config = { | ||
| transitionTime: 300, | ||
| loaderSpeed: 500, | ||
| waitingTime: 1e3 | ||
| }; | ||
| subscribe(listener) { | ||
@@ -23,17 +33,32 @@ this.listeners.add(listener); | ||
| } | ||
| start() { | ||
| if (this.value !== null) return; | ||
| start(loaderType = "continuous") { | ||
| if (loaderType === "static") { | ||
| this.staticStart(); | ||
| } else { | ||
| this.continuousStart(); | ||
| } | ||
| } | ||
| continuousStart(startingValue, refreshRate) { | ||
| this.cleanup(); | ||
| this.value = 10; | ||
| this.value = startingValue !== void 0 ? startingValue : Math.floor(Math.random() * 10) + 20; | ||
| this.notify(); | ||
| this.interval = setInterval(() => { | ||
| if (this.value !== null) { | ||
| const amount = Math.max(0.5, (95 - this.value) / 10); | ||
| this.value = Math.min(this.value + amount, 95); | ||
| if (this.value !== null && this.value < 90) { | ||
| const inc = Math.floor(Math.random() * 8) + 2; | ||
| this.value = Math.min(this.value + inc, 90); | ||
| this.notify(); | ||
| } | ||
| }, 200); | ||
| }, refreshRate || this.config.loaderSpeed); | ||
| } | ||
| staticStart(startingValue) { | ||
| this.cleanup(); | ||
| this.value = startingValue !== void 0 ? startingValue : Math.floor(Math.random() * 20) + 30; | ||
| this.notify(); | ||
| } | ||
| complete() { | ||
| this.finish(); | ||
| } | ||
| finish() { | ||
| this.cleanup(); | ||
| if (this.value === null) return; | ||
| this.value = 100; | ||
@@ -44,4 +69,25 @@ this.notify(); | ||
| this.notify(); | ||
| }, 400); | ||
| }, this.config.waitingTime); | ||
| } | ||
| set(value) { | ||
| this.cleanup(); | ||
| this.value = value; | ||
| this.notify(); | ||
| if (value >= 100) { | ||
| this.finish(); | ||
| } | ||
| } | ||
| increase(amount) { | ||
| if (this.value !== null) { | ||
| this.value = Math.min(this.value + amount, 100); | ||
| this.notify(); | ||
| if (this.value === 100) this.finish(); | ||
| } | ||
| } | ||
| decrease(amount) { | ||
| if (this.value !== null) { | ||
| this.value = Math.max(0, this.value - amount); | ||
| this.notify(); | ||
| } | ||
| } | ||
| cleanup() { | ||
@@ -54,7 +100,17 @@ if (this.interval) clearInterval(this.interval); | ||
| } | ||
| getProgress() { | ||
| return this.value; | ||
| } | ||
| }; | ||
| var progressStore = new ProgressStore(); | ||
| var useProgressStore = () => progressStore; | ||
| var startProgress = () => progressStore.start(); | ||
| var startProgress = (type) => progressStore.start(type); | ||
| var continuousStart = (startingValue, refreshRate) => progressStore.continuousStart(startingValue, refreshRate); | ||
| var staticStart = (startingValue) => progressStore.staticStart(startingValue); | ||
| var finishProgress = () => progressStore.finish(); | ||
| var completeProgress = () => progressStore.complete(); | ||
| var increaseProgress = (value) => progressStore.increase(value); | ||
| var decreaseProgress = (value) => progressStore.decrease(value); | ||
| var getProgress = () => progressStore.getProgress(); | ||
| var setProgress = (value) => progressStore.set(value); | ||
| var withProgress = async (promise) => { | ||
@@ -74,66 +130,121 @@ startProgress(); | ||
| import { jsx } from "react/jsx-runtime"; | ||
| var TopProgress = ({ | ||
| color = "#29D", | ||
| // Still the default flat color, but can now accept "linear-gradient(...)" | ||
| height = 3, | ||
| showGlow = true, | ||
| glowColor, | ||
| zIndex = 9999 | ||
| }) => { | ||
| const store = useProgressStore(); | ||
| const [progress, setProgress] = useState(store.getValue()); | ||
| useEffect(() => { | ||
| return store.subscribe(setProgress); | ||
| }, [store]); | ||
| if (progress === null) { | ||
| return null; | ||
| var TopProgress = forwardRef( | ||
| ({ | ||
| progress: controlledProgress, | ||
| color = "red", | ||
| shadow = true, | ||
| height = 2, | ||
| background = "transparent", | ||
| style, | ||
| containerStyle, | ||
| shadowStyle, | ||
| transitionTime = 300, | ||
| loaderSpeed = 500, | ||
| waitingTime = 1e3, | ||
| className, | ||
| containerClassName, | ||
| onLoaderFinished, | ||
| showGlow, | ||
| glowColor, | ||
| zIndex = 9999 | ||
| }, ref) => { | ||
| const store = useProgressStore(); | ||
| const [internalProgress, setInternalProgress] = useState( | ||
| store.getValue() | ||
| ); | ||
| useImperativeHandle(ref, () => ({ | ||
| start: (type) => store.start(type), | ||
| continuousStart: (s, r) => store.continuousStart(s, r), | ||
| staticStart: (s) => store.staticStart(s), | ||
| complete: () => store.complete(), | ||
| increase: (v) => store.increase(v), | ||
| decrease: (v) => store.decrease(v), | ||
| getProgress: () => store.getProgress(), | ||
| set: (v) => store.set(v) | ||
| })); | ||
| useEffect(() => { | ||
| store.config.transitionTime = transitionTime; | ||
| store.config.loaderSpeed = loaderSpeed; | ||
| store.config.waitingTime = waitingTime; | ||
| }, [transitionTime, loaderSpeed, waitingTime, store]); | ||
| useEffect(() => { | ||
| return store.subscribe(setInternalProgress); | ||
| }, [store]); | ||
| const progress = controlledProgress !== void 0 ? controlledProgress : internalProgress; | ||
| useEffect(() => { | ||
| if (progress === 100 && onLoaderFinished) { | ||
| onLoaderFinished(); | ||
| } | ||
| }, [progress, onLoaderFinished]); | ||
| if (progress === null) { | ||
| return null; | ||
| } | ||
| const isGradient = color.includes("gradient("); | ||
| const backgroundStyle = isGradient ? { backgroundImage: color } : { backgroundColor: color }; | ||
| const useShadow = showGlow !== void 0 ? showGlow : shadow; | ||
| const computedGlowColor = glowColor || (isGradient ? "rgba(41, 216, 255, 0.4)" : color); | ||
| return /* @__PURE__ */ jsx( | ||
| "div", | ||
| { | ||
| className: containerClassName, | ||
| style: { | ||
| position: "fixed", | ||
| top: 0, | ||
| left: 0, | ||
| width: "100%", | ||
| height: `${height}px`, | ||
| backgroundColor: background, | ||
| zIndex, | ||
| pointerEvents: "none", | ||
| ...containerStyle | ||
| }, | ||
| children: /* @__PURE__ */ jsx( | ||
| "div", | ||
| { | ||
| className, | ||
| style: { | ||
| width: `${progress}%`, | ||
| height: "100%", | ||
| ...backgroundStyle, | ||
| transition: `width ${loaderSpeed}ms cubic-bezier(0.4, 0, 0.2, 1), opacity ${transitionTime}ms ease`, | ||
| opacity: progress === 100 ? 0 : 1, | ||
| transform: "translateZ(0)", | ||
| ...style | ||
| }, | ||
| children: /* @__PURE__ */ jsx( | ||
| "div", | ||
| { | ||
| style: { | ||
| display: useShadow ? "block" : "none", | ||
| position: "absolute", | ||
| right: 0, | ||
| top: 0, | ||
| width: 100, | ||
| height: "100%", | ||
| boxShadow: `0 0 10px ${computedGlowColor}, 0 0 5px ${computedGlowColor}`, | ||
| opacity: 1, | ||
| transform: "rotate(3deg) translate(0px, -4px)", | ||
| ...shadowStyle | ||
| } | ||
| } | ||
| ) | ||
| } | ||
| ) | ||
| } | ||
| ); | ||
| } | ||
| const isGradient = color.includes("gradient("); | ||
| const backgroundStyle = isGradient ? { backgroundImage: color } : { backgroundColor: color }; | ||
| const computedGlowColor = glowColor || (isGradient ? "rgba(41, 216, 255, 0.4)" : color); | ||
| return /* @__PURE__ */ jsx( | ||
| "div", | ||
| { | ||
| style: { | ||
| position: "fixed", | ||
| top: 0, | ||
| left: 0, | ||
| width: `${progress}%`, | ||
| height: `${height}px`, | ||
| ...backgroundStyle, | ||
| // Box shadow generates a beautiful diffused glow underneath the progress bar | ||
| boxShadow: showGlow ? `0 0 10px ${computedGlowColor}, 0 0 5px ${computedGlowColor}` : "none", | ||
| // Smooth and performant 60fps CSS transitions | ||
| transition: "width 0.2s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.4s ease", | ||
| opacity: progress === 100 ? 0 : 1, | ||
| zIndex, | ||
| // Force hardware acceleration for paint performance | ||
| transform: "translateZ(0)", | ||
| // Don't intercept clicks | ||
| pointerEvents: "none" | ||
| }, | ||
| children: /* @__PURE__ */ jsx( | ||
| "div", | ||
| { | ||
| style: { | ||
| display: showGlow ? "block" : "none", | ||
| position: "absolute", | ||
| right: 0, | ||
| top: 0, | ||
| width: 100, | ||
| height: "100%", | ||
| boxShadow: `0 0 10px ${computedGlowColor}, 0 0 5px ${computedGlowColor}`, | ||
| opacity: 1, | ||
| transform: "rotate(3deg) translate(0px, -4px)" | ||
| } | ||
| } | ||
| ) | ||
| } | ||
| ); | ||
| }; | ||
| ); | ||
| TopProgress.displayName = "TopProgress"; | ||
| export { | ||
| TopProgress, | ||
| completeProgress, | ||
| continuousStart, | ||
| decreaseProgress, | ||
| finishProgress, | ||
| getProgress, | ||
| increaseProgress, | ||
| setProgress, | ||
| startProgress, | ||
| staticStart, | ||
| withProgress | ||
| }; |
+2
-2
| { | ||
| "name": "react-top-progress", | ||
| "version": "0.1.1", | ||
| "version": "1.0.0", | ||
| "description": "A lightweight modern top loading progress bar for React", | ||
@@ -10,3 +10,3 @@ "main": "dist/index.js", | ||
| "dist", | ||
| "demo_react_top_progress.png" | ||
| "demo_react_top_progress.webp" | ||
| ], | ||
@@ -13,0 +13,0 @@ "keywords": [ |
+51
-45
| # react-top-progress | ||
|  | ||
| **<a href="https://react-test-progress.vercel.app/" target="_blank">👉 View Live Demo</a>** | ||
| **[👉 View Live Demo](https://react-test-progress.vercel.app/)** | ||
| A lightweight, modern, and performant top loading progress bar for React. Built for seamless user experiences with zero dependencies! | ||
| A lightweight, modern, and performant top loading progress bar for React. | ||
| Perfect for Next.js App Router, Vite, and standard SPA architectures. | ||
| Perfect for Next.js App Router, Vite, and standard single-page applications. | ||
| ## Features | ||
| - **0 dependencies**: Tiny footprint (~1kb gzipped). | ||
| - **Realistic loading feel**: Increments incrementally like real network requests. | ||
| - **Premium DX**: Controlled programmatically with simple `startProgress` / `finishProgress` API. | ||
| - **Gradient & Glow Support**: Fully customizable colors, shadow pegs, and effects. | ||
| - **Performant**: Uses `transform` hardware acceleration and `cubic-bezier` transitions. | ||
| - **0 Dependencies**: Tiny footprint (~1.8kb gzipped). | ||
| - **Advanced Loaders**: `continuous` and `static` start modes matching network logic. | ||
| - **Premium DX**: Controlled programmatically with simple global API hooks, or direct React `ref`. | ||
| - **Customizable**: Add gradients, background container colors, custom CSS classes, and glows. | ||
| - **Performant**: Uses `transform: translateZ(0)` hardware acceleration and `cubic-bezier` CSS transitions. | ||
| - **TypeScript ready**: Full types included. | ||
| - **React 18+ & Next.js ready**: Contains `"use client"` where necessary. | ||
@@ -37,6 +34,4 @@ ## Installation | ||
| ### 1. Add the component to your root layout/app | ||
| At the top level of your application (like Next.js `app/layout.tsx` or Vite `src/App.tsx`), render the component. | ||
| At the top level of your application (like Next.js `app/layout.tsx` or Vite `src/App.tsx`), render the `<TopProgress />` component. | ||
| ```tsx | ||
@@ -57,50 +52,61 @@ import { TopProgress } from "react-top-progress"; | ||
| ### 2. Control it programmatically | ||
| ## Built-in Methods | ||
| Import the API from anywhere in your app to trigger the progress bar manually! | ||
| 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} />`. | ||
| | Method | Parameters | Description | | ||
| | ------ | ---------- | ----------- | | ||
| | `start(loaderType?)` | `"continuous" \| "static"` | Starts the loading indicator. Default is continuous. | | ||
| | `continuousStart(startingValue?, refreshRate?)` | `number`, `number` | Starts with a random value (20-30), then slowly ticks up (2-10) repetitively. Reaches max 90%. | | ||
| | `staticStart(startingValue?)` | `number` | Starts the loader with a random static value between 30-50, waiting for completion. | | ||
| | `complete()` / `finishProgress()` | | Instantly pushes the indicator to 100% and gracefully fades it out. | | ||
| | `increase(value)` | `number` | Manually increments the loader by a specific amount. | | ||
| | `decrease(value)` | `number` | Manually decrements the loader by a specific amount. | | ||
| | `setProgress(value)` | `number` | Hardsets to a specific progress percentage. | | ||
| | `getProgress()` | | Returns the current progress percentage (0 - 100). | | ||
| | `withProgress(promise)`| `Promise<T>` | Wraps an asynchronous action. `startProgress()` executes automatically before and completes automatically afterward. | | ||
| ### Global Usage Example | ||
| ```tsx | ||
| import { startProgress, finishProgress } from "react-top-progress"; | ||
| import { startProgress, finishProgress, withProgress } from "react-top-progress"; | ||
| async function handleAction() { | ||
| startProgress(); | ||
| async function fetchData() { | ||
| startProgress("continuous"); | ||
| try { | ||
| await someHeavyTask(); | ||
| await apiCall(); | ||
| } finally { | ||
| finishProgress(); | ||
| finishProgress(); // alias of complete() | ||
| } | ||
| } | ||
| ``` | ||
| ### 3. The `withProgress` Utility | ||
| For an even better Developer Experience, simply wrap your promises securely with `withProgress`! | ||
| ```tsx | ||
| import { withProgress } from "react-top-progress"; | ||
| async function handleFetch() { | ||
| const data = await withProgress(fetch("/api/data")); | ||
| console.log(data); | ||
| } | ||
| // Or functionally wrap promises for ultimate DX: | ||
| const loadProfile = () => withProgress(fetch("/api/profile")); | ||
| ``` | ||
| ## Customization API | ||
| ## Component Properties | ||
| The `TopProgress` component accepts the following props: | ||
| You can customize `<TopProgress />` passing any of the following props: | ||
| | Prop | Type | Default | Description | | ||
| | ----------- | --------- | ----------- | ------------------------------------------------------------------------------------------------------------ | | ||
| | `color` | `string` | `"#29D"` | Flat hex color or `linear-gradient(...)` function string | | ||
| | `height` | `number` | `3` | Height of the progress bar in pixels | | ||
| | `showGlow` | `boolean` | `true` | Whether to display the premium box-shadow drop-glow and trailing peg | | ||
| | `glowColor` | `string` | `undefined` | Optionally override the color of the glow effect. By default, it infers realistically from your main `color` | | ||
| | `zIndex` | `number` | `9999` | The z-index stacking context level. | | ||
| | Property | Type | Default | Description | | ||
| | -------- | ---- | ------- | ----------- | | ||
| | `progress` | `number` | | Hardset the progress (0-100) if you want to bypass the internal store and control state yourself. | | ||
| | `color` | `string` | `"red"` | Background color of the bar. Accepts `linear-gradient(...)` or hex codes. | | ||
| | `height` | `number` | `2` | Height of the progress bar in pixels. | | ||
| | `shadow` | `boolean` | `true` | Appends a glorious trailing drop-glow peg matching the bar's color tracking its head. | | ||
| | `background` | `string` | `"transparent"` | Fills the container div's background layer under the progress element. | | ||
| | `transitionTime` | `number` | `300` | Fade transition time (ms) for the fade-out completion sequence. | | ||
| | `loaderSpeed` | `number` | `500` | Loader width transition speed (ms). | | ||
| | `waitingTime` | `number` | `1000` | The delay time (ms) loader waits at 100% width before fading entirely out. | | ||
| | `style` | `CSSProperties` | | Inject custom JSX styles directly onto the loader element. | | ||
| | `className` | `string` | | Apply a specific custom CSS class to the loader element. | | ||
| | `containerStyle` | `CSSProperties` | | Configure inline styles for the fixed `<div />` wrapper container. | | ||
| | `containerClassName` | `string` | | Custom CSS class applied onto the wrapper container. | | ||
| | `onLoaderFinished` | `() => void` | | A callback function executing precisely when the loader fully hits 100% max width. | | ||
| ## Credits & Inspiration | ||
| ## Credits | ||
| 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. | ||
| Inspired by standard `nprogress` and optimized libraries like `react-top-loading-bar` / `nextjs-toploader`, rewritten entirely from scratch for the cleanest Developer Experience. | ||
| ## License | ||
| MIT |
Sorry, the diff of this file is not supported yet
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
556
83.5%1
-50%111
5.71%54294
-43.1%