@tanem/react-nprogress 6.0.4 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +114 -108
- package/dist/react-nprogress.cjs +124 -0
- package/dist/react-nprogress.cjs.map +1 -0
- package/dist/react-nprogress.d.cts +26 -0
- package/dist/react-nprogress.d.cts.map +1 -0
- package/dist/react-nprogress.d.mts +26 -0
- package/dist/react-nprogress.d.mts.map +1 -0
- package/dist/react-nprogress.mjs +122 -0
- package/dist/react-nprogress.mjs.map +1 -0
- package/package.json +50 -36
- package/src/NProgress.tsx +13 -0
- package/src/clamp.ts +5 -0
- package/src/createTimeout.ts +35 -0
- package/src/env.d.ts +0 -0
- package/src/increment.ts +17 -0
- package/src/index.tsx +3 -0
- package/src/types.ts +13 -0
- package/src/useNProgress.tsx +137 -0
- package/dist/NProgress.d.ts +0 -8
- package/dist/clamp.d.ts +0 -1
- package/dist/createQueue.d.ts +0 -7
- package/dist/createTimeout.d.ts +0 -4
- package/dist/increment.d.ts +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -7
- package/dist/react-nprogress.cjs.development.js +0 -299
- package/dist/react-nprogress.cjs.development.js.map +0 -1
- package/dist/react-nprogress.cjs.production.js +0 -2
- package/dist/react-nprogress.cjs.production.js.map +0 -1
- package/dist/react-nprogress.esm.js +0 -295
- package/dist/react-nprogress.esm.js.map +0 -1
- package/dist/react-nprogress.umd.development.js +0 -727
- package/dist/react-nprogress.umd.development.js.map +0 -1
- package/dist/react-nprogress.umd.production.js +0 -2
- package/dist/react-nprogress.umd.production.js.map +0 -1
- package/dist/types.d.ts +0 -6
- package/dist/useEffectOnce.d.ts +0 -2
- package/dist/useGetSetState.d.ts +0 -1
- package/dist/useNProgress.d.ts +0 -6
- package/dist/useUpdateEffect.d.ts +0 -2
- package/dist/withNProgress.d.ts +0 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-nprogress.mjs","names":["defaultIncrement","increment"],"sources":["../src/clamp.ts","../src/createTimeout.ts","../src/increment.ts","../src/useNProgress.tsx","../src/NProgress.tsx"],"sourcesContent":["export const clamp = (num: number, lower: number, upper: number): number => {\n num = num <= upper ? num : upper\n num = num >= lower ? num : lower\n return num\n}\n","// Uses requestAnimationFrame rather than setTimeout for smoother animation\n// timing. Note that rAF is throttled or paused in background tabs, so progress\n// will stall when the tab is hidden and resume when it regains focus.\nexport const createTimeout = () => {\n let handle: number | undefined\n\n const cancel = (): void => {\n if (handle !== undefined) {\n window.cancelAnimationFrame(handle)\n }\n }\n\n const schedule = (callback: () => void, delay: number): void => {\n cancel()\n\n let deltaTime\n let start: number | undefined\n const frame: FrameRequestCallback = (time) => {\n start = start || time\n deltaTime = time - start\n if (deltaTime > delay) {\n callback()\n return\n }\n handle = window.requestAnimationFrame(frame)\n }\n\n handle = window.requestAnimationFrame(frame)\n }\n\n return {\n cancel,\n schedule,\n }\n}\n","import { clamp } from './clamp'\n\nexport const increment = (progress: number): number => {\n let amount = 0\n\n if (progress >= 0 && progress < 0.2) {\n amount = 0.1\n } else if (progress >= 0.2 && progress < 0.5) {\n amount = 0.04\n } else if (progress >= 0.5 && progress < 0.8) {\n amount = 0.02\n } else if (progress >= 0.8 && progress < 0.99) {\n amount = 0.005\n }\n\n return clamp(progress + amount, 0, 0.994)\n}\n","import { useEffect, useReducer, useRef } from 'react'\n\nimport { clamp } from './clamp'\nimport { createTimeout } from './createTimeout'\nimport { increment as defaultIncrement } from './increment'\nimport type { NProgressOptions, NProgressState } from './types'\n\n// A four-phase state machine. `idle` and `finished` both report\n// `isFinished: true` and differ only in the progress they hold, so the phase,\n// not `isFinished`, is what decides which transitions and timers apply.\ntype Phase = 'animating' | 'completing' | 'finished' | 'idle'\n\ninterface State {\n phase: Phase\n progress: number\n}\n\ntype Action =\n | {\n increment: (progress: number) => number\n minimum: number\n type: 'trickle'\n }\n | { minimum: number; type: 'start' }\n | { type: 'complete' }\n | { type: 'finish' }\n\nconst initialState: State = {\n phase: 'idle',\n progress: 0,\n}\n\nconst reducer = (state: State, action: Action): State => {\n switch (action.type) {\n case 'complete':\n // The original nprogress `done()` computes a random progress jump before\n // animating to 1, but its queue runs both steps in the same tick, so the\n // jump's CSS is overwritten before paint and never renders. Omitting the\n // jump changes nothing visually.\n //\n // Ignored unless an animation is actually running, which is what makes a\n // StrictMode double-mount a no-op rather than a spurious completion.\n return state.phase === 'animating'\n ? { phase: 'completing', progress: 1 }\n : state\n\n case 'finish':\n return { phase: 'finished', progress: 1 }\n\n case 'start':\n // Matches the original nprogress `start()`, which calls set(0) and so\n // paints first at `minimum` before any trickle runs.\n //\n // Guarded the same way as `complete`, and for the same reason: a repeat\n // dispatch against a running animation must not rewind the bar. That\n // happens whenever `minimum` changes mid-animation, as well as on a\n // StrictMode double-mount.\n return state.phase === 'animating'\n ? state\n : {\n phase: 'animating',\n progress: clamp(0, action.minimum, 1),\n }\n\n case 'trickle':\n // Clamped here rather than trusted from the increment function, so a\n // custom one cannot take the bar outside the documented range. Stopping\n // short of 1 is that function's own business: 1 is what completion\n // means.\n return {\n ...state,\n progress: clamp(action.increment(state.progress), action.minimum, 1),\n }\n }\n}\n\nexport const useNProgress = ({\n animationDuration = 200,\n increment = defaultIncrement,\n incrementDuration = 200,\n isAnimating = false,\n minimum = 0.08,\n}: NProgressOptions = {}): NProgressState => {\n const [{ phase, progress }, dispatch] = useReducer(reducer, initialState)\n\n // Held in a ref so the trickle timer can read the latest increment function\n // without listing it as a dependency. Consumers commonly pass an inline\n // function, whose identity changes every render; depending on it directly\n // would cancel and recreate the timer each time, and a render loop faster\n // than `incrementDuration` would stop the bar advancing altogether.\n const incrementRef = useRef(increment)\n useEffect(() => {\n incrementRef.current = increment\n })\n\n useEffect(() => {\n dispatch(isAnimating ? { minimum, type: 'start' } : { type: 'complete' })\n }, [isAnimating, minimum])\n\n // A timer per running phase, rather than one effect branching over both.\n // Each then depends only on the options its own phase reads, so changing an\n // option the running phase ignores cannot cancel its timer. Both are keyed\n // on the phase rather than on progress, so trickling does not tear down and\n // recreate the timer mid-animation.\n useEffect(() => {\n if (phase !== 'animating') {\n return\n }\n\n const timeout = createTimeout()\n\n const trickle = () => {\n dispatch({ increment: incrementRef.current, minimum, type: 'trickle' })\n timeout.schedule(trickle, incrementDuration)\n }\n timeout.schedule(trickle, incrementDuration)\n\n return () => timeout.cancel()\n }, [incrementDuration, minimum, phase])\n\n useEffect(() => {\n if (phase !== 'completing') {\n return\n }\n\n const timeout = createTimeout()\n timeout.schedule(() => dispatch({ type: 'finish' }), animationDuration)\n\n return () => timeout.cancel()\n }, [animationDuration, phase])\n\n return {\n animationDuration,\n isFinished: phase === 'finished' || phase === 'idle',\n progress,\n }\n}\n","import type { FC, ReactElement } from 'react'\n\nimport type { NProgressOptions, NProgressState } from './types'\nimport { useNProgress } from './useNProgress'\n\ntype Props = NProgressOptions & {\n children: (renderProps: NProgressState) => ReactElement\n}\n\nexport const NProgress: FC<Props> = ({ children, ...restProps }: Props) => {\n const renderProps = useNProgress(restProps)\n return children(renderProps)\n}\n"],"mappings":";;;AAAA,MAAa,SAAS,KAAa,OAAe,UAA0B;CAC1E,MAAM,OAAO,QAAQ,MAAM;CAC3B,MAAM,OAAO,QAAQ,MAAM;CAC3B,OAAO;AACT;;;ACDA,MAAa,sBAAsB;CACjC,IAAI;CAEJ,MAAM,eAAqB;EACzB,IAAI,WAAW,KAAA,GACb,OAAO,qBAAqB,MAAM;CAEtC;CAEA,MAAM,YAAY,UAAsB,UAAwB;EAC9D,OAAO;EAEP,IAAI;EACJ,IAAI;EACJ,MAAM,SAA+B,SAAS;GAC5C,QAAQ,SAAS;GACjB,YAAY,OAAO;GACnB,IAAI,YAAY,OAAO;IACrB,SAAS;IACT;GACF;GACA,SAAS,OAAO,sBAAsB,KAAK;EAC7C;EAEA,SAAS,OAAO,sBAAsB,KAAK;CAC7C;CAEA,OAAO;EACL;EACA;CACF;AACF;;;AChCA,MAAa,aAAa,aAA6B;CACrD,IAAI,SAAS;CAEb,IAAI,YAAY,KAAK,WAAW,IAC9B,SAAS;MACJ,IAAI,YAAY,MAAO,WAAW,IACvC,SAAS;MACJ,IAAI,YAAY,MAAO,WAAW,IACvC,SAAS;MACJ,IAAI,YAAY,MAAO,WAAW,KACvC,SAAS;CAGX,OAAO,MAAM,WAAW,QAAQ,GAAG,IAAK;AAC1C;;;ACWA,MAAM,eAAsB;CAC1B,OAAO;CACP,UAAU;AACZ;AAEA,MAAM,WAAW,OAAc,WAA0B;CACvD,QAAQ,OAAO,MAAf;EACE,KAAK,YAQH,OAAO,MAAM,UAAU,cACnB;GAAE,OAAO;GAAc,UAAU;EAAE,IACnC;EAEN,KAAK,UACH,OAAO;GAAE,OAAO;GAAY,UAAU;EAAE;EAE1C,KAAK,SAQH,OAAO,MAAM,UAAU,cACnB,QACA;GACE,OAAO;GACP,UAAU,MAAM,GAAG,OAAO,SAAS,CAAC;EACtC;EAEN,KAAK,WAKH,OAAO;GACL,GAAG;GACH,UAAU,MAAM,OAAO,UAAU,MAAM,QAAQ,GAAG,OAAO,SAAS,CAAC;EACrE;CACJ;AACF;AAEA,MAAa,gBAAgB,EAC3B,oBAAoB,KACpB,WAAA,cAAYA,WACZ,oBAAoB,KACpB,cAAc,OACd,UAAU,QACU,CAAC,MAAsB;CAC3C,MAAM,CAAC,EAAE,OAAO,YAAY,YAAY,WAAW,SAAS,YAAY;CAOxE,MAAM,eAAe,OAAOC,WAAS;CACrC,gBAAgB;EACd,aAAa,UAAUA;CACzB,CAAC;CAED,gBAAgB;EACd,SAAS,cAAc;GAAE;GAAS,MAAM;EAAQ,IAAI,EAAE,MAAM,WAAW,CAAC;CAC1E,GAAG,CAAC,aAAa,OAAO,CAAC;CAOzB,gBAAgB;EACd,IAAI,UAAU,aACZ;EAGF,MAAM,UAAU,cAAc;EAE9B,MAAM,gBAAgB;GACpB,SAAS;IAAE,WAAW,aAAa;IAAS;IAAS,MAAM;GAAU,CAAC;GACtE,QAAQ,SAAS,SAAS,iBAAiB;EAC7C;EACA,QAAQ,SAAS,SAAS,iBAAiB;EAE3C,aAAa,QAAQ,OAAO;CAC9B,GAAG;EAAC;EAAmB;EAAS;CAAK,CAAC;CAEtC,gBAAgB;EACd,IAAI,UAAU,cACZ;EAGF,MAAM,UAAU,cAAc;EAC9B,QAAQ,eAAe,SAAS,EAAE,MAAM,SAAS,CAAC,GAAG,iBAAiB;EAEtE,aAAa,QAAQ,OAAO;CAC9B,GAAG,CAAC,mBAAmB,KAAK,CAAC;CAE7B,OAAO;EACL;EACA,YAAY,UAAU,cAAc,UAAU;EAC9C;CACF;AACF;;;AC/HA,MAAa,aAAwB,EAAE,UAAU,GAAG,gBAAuB;CAEzE,OAAO,SADa,aAAa,SACP,CAAC;AAC7B"}
|
package/package.json
CHANGED
|
@@ -1,40 +1,67 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanem/react-nprogress",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.1.0",
|
|
4
4
|
"description": "A React primitive for building slim progress bars.",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": {
|
|
9
|
+
"types": "./dist/react-nprogress.d.mts",
|
|
10
|
+
"default": "./dist/react-nprogress.mjs"
|
|
11
|
+
},
|
|
12
|
+
"default": {
|
|
13
|
+
"types": "./dist/react-nprogress.d.cts",
|
|
14
|
+
"default": "./dist/react-nprogress.cjs"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"./package.json": "./package.json"
|
|
18
|
+
},
|
|
19
|
+
"main": "dist/react-nprogress.cjs",
|
|
20
|
+
"module": "dist/react-nprogress.mjs",
|
|
21
|
+
"types": "dist/react-nprogress.d.cts",
|
|
8
22
|
"sideEffects": false,
|
|
23
|
+
"size-limit": [
|
|
24
|
+
{
|
|
25
|
+
"name": "ESM bundle",
|
|
26
|
+
"path": "dist/react-nprogress.mjs",
|
|
27
|
+
"gzip": true,
|
|
28
|
+
"limit": "1.2 kB"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"name": "CJS bundle",
|
|
32
|
+
"path": "dist/react-nprogress.cjs",
|
|
33
|
+
"gzip": true,
|
|
34
|
+
"limit": "1.3 kB"
|
|
35
|
+
}
|
|
36
|
+
],
|
|
9
37
|
"files": [
|
|
10
|
-
"dist"
|
|
38
|
+
"dist",
|
|
39
|
+
"src"
|
|
11
40
|
],
|
|
12
41
|
"scripts": {
|
|
13
42
|
"authors": "tanem-scripts authors > AUTHORS",
|
|
14
|
-
"build": "run-s clean
|
|
15
|
-
"bundle": "
|
|
43
|
+
"build": "run-s clean bundle",
|
|
44
|
+
"bundle": "tsdown",
|
|
16
45
|
"changelog": "tanem-scripts changelog -f v$npm_package_version > CHANGELOG.md",
|
|
17
|
-
"check:format": "prettier --list-different \"**/*.{js,ts,tsx}\"",
|
|
46
|
+
"check:format": "prettier --list-different \"**/*.{cjs,cts,js,mjs,mts,ts,tsx}\"",
|
|
18
47
|
"check:types": "tsc --noEmit",
|
|
19
48
|
"clean": "run-p clean:*",
|
|
20
|
-
"clean:compiled": "shx rm -rf compiled",
|
|
21
49
|
"clean:coverage": "shx rm -rf coverage",
|
|
22
|
-
"clean:dist": "shx rm -rf dist",
|
|
23
50
|
"clean:react": "node ./scripts/clean-react.js",
|
|
24
|
-
"
|
|
25
|
-
"format": "eslint . --fix && prettier --write \"**/*.{js,ts,tsx}\"",
|
|
51
|
+
"format": "eslint . --fix && prettier --write \"**/*.{cjs,cts,js,mjs,mts,ts,tsx}\"",
|
|
26
52
|
"lint": "eslint . --max-warnings=0",
|
|
27
|
-
"
|
|
53
|
+
"package:attw": "node ./scripts/attw.js",
|
|
54
|
+
"package:publint": "publint",
|
|
55
|
+
"postbuild": "run-s package:*",
|
|
28
56
|
"prepare": "npm run build",
|
|
29
57
|
"release": "tanem-scripts release",
|
|
30
|
-
"
|
|
58
|
+
"size": "size-limit",
|
|
59
|
+
"test": "run-s check:* lint build size test:*",
|
|
60
|
+
"test:bundles": "jest --config ./scripts/jest/config.bundles.js",
|
|
31
61
|
"test:cjs": "jest --config ./scripts/jest/config.cjs.js",
|
|
32
|
-
"test:
|
|
33
|
-
"test:es": "jest --config ./scripts/jest/config.es.js",
|
|
62
|
+
"test:es": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --config ./scripts/jest/config.es.js",
|
|
34
63
|
"test:react": "node ./scripts/test-react.js",
|
|
35
64
|
"test:src": "jest --config ./scripts/jest/config.src.js",
|
|
36
|
-
"test:umd": "jest --config ./scripts/jest/config.umd.js",
|
|
37
|
-
"test:umdprod": "jest --config ./scripts/jest/config.umdprod.js",
|
|
38
65
|
"version": "run-s test changelog authors && git add ."
|
|
39
66
|
},
|
|
40
67
|
"repository": {
|
|
@@ -44,8 +71,6 @@
|
|
|
44
71
|
"keywords": [
|
|
45
72
|
"animation",
|
|
46
73
|
"component",
|
|
47
|
-
"higher-order-component",
|
|
48
|
-
"hoc",
|
|
49
74
|
"hook",
|
|
50
75
|
"hooks",
|
|
51
76
|
"javascript",
|
|
@@ -70,25 +95,12 @@
|
|
|
70
95
|
"overrides": {
|
|
71
96
|
"brace-expansion": "^5.0.8"
|
|
72
97
|
},
|
|
73
|
-
"dependencies": {
|
|
74
|
-
"@babel/runtime": "^7.28.6",
|
|
75
|
-
"hoist-non-react-statics": "^3.3.2"
|
|
76
|
-
},
|
|
77
98
|
"devDependencies": {
|
|
78
|
-
"@
|
|
79
|
-
"@babel/plugin-transform-runtime": "7.29.0",
|
|
80
|
-
"@babel/preset-env": "7.29.0",
|
|
81
|
-
"@babel/preset-react": "7.28.5",
|
|
82
|
-
"@babel/preset-typescript": "7.28.5",
|
|
99
|
+
"@arethetypeswrong/cli": "0.18.5",
|
|
83
100
|
"@eslint-react/eslint-plugin": "5.18.0",
|
|
84
101
|
"@eslint/js": "10.0.1",
|
|
85
|
-
"@
|
|
86
|
-
"@rollup/plugin-commonjs": "29.0.0",
|
|
87
|
-
"@rollup/plugin-node-resolve": "16.0.3",
|
|
88
|
-
"@rollup/plugin-replace": "6.0.3",
|
|
89
|
-
"@rollup/plugin-terser": "1.0.0",
|
|
102
|
+
"@size-limit/file": "13.0.2",
|
|
90
103
|
"@testing-library/react": "16.3.2",
|
|
91
|
-
"@types/hoist-non-react-statics": "3.3.7",
|
|
92
104
|
"@types/jest": "30.0.0",
|
|
93
105
|
"@types/mock-raf": "1.0.6",
|
|
94
106
|
"@types/node": "24.11.0",
|
|
@@ -105,12 +117,14 @@
|
|
|
105
117
|
"mock-raf": "1.0.1",
|
|
106
118
|
"npm-run-all2": "8.0.4",
|
|
107
119
|
"prettier": "3.8.1",
|
|
120
|
+
"publint": "0.3.22",
|
|
108
121
|
"react": "19.2.4",
|
|
109
122
|
"react-dom": "19.2.4",
|
|
110
|
-
"rollup": "4.59.0",
|
|
111
123
|
"shx": "0.4.0",
|
|
124
|
+
"size-limit": "13.0.2",
|
|
112
125
|
"tanem-scripts": "8.0.4",
|
|
113
126
|
"ts-jest": "29.4.6",
|
|
127
|
+
"tsdown": "0.22.14",
|
|
114
128
|
"typescript": "5.9.3",
|
|
115
129
|
"typescript-eslint": "8.56.1"
|
|
116
130
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { FC, ReactElement } from 'react'
|
|
2
|
+
|
|
3
|
+
import type { NProgressOptions, NProgressState } from './types'
|
|
4
|
+
import { useNProgress } from './useNProgress'
|
|
5
|
+
|
|
6
|
+
type Props = NProgressOptions & {
|
|
7
|
+
children: (renderProps: NProgressState) => ReactElement
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const NProgress: FC<Props> = ({ children, ...restProps }: Props) => {
|
|
11
|
+
const renderProps = useNProgress(restProps)
|
|
12
|
+
return children(renderProps)
|
|
13
|
+
}
|
package/src/clamp.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Uses requestAnimationFrame rather than setTimeout for smoother animation
|
|
2
|
+
// timing. Note that rAF is throttled or paused in background tabs, so progress
|
|
3
|
+
// will stall when the tab is hidden and resume when it regains focus.
|
|
4
|
+
export const createTimeout = () => {
|
|
5
|
+
let handle: number | undefined
|
|
6
|
+
|
|
7
|
+
const cancel = (): void => {
|
|
8
|
+
if (handle !== undefined) {
|
|
9
|
+
window.cancelAnimationFrame(handle)
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const schedule = (callback: () => void, delay: number): void => {
|
|
14
|
+
cancel()
|
|
15
|
+
|
|
16
|
+
let deltaTime
|
|
17
|
+
let start: number | undefined
|
|
18
|
+
const frame: FrameRequestCallback = (time) => {
|
|
19
|
+
start = start || time
|
|
20
|
+
deltaTime = time - start
|
|
21
|
+
if (deltaTime > delay) {
|
|
22
|
+
callback()
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
handle = window.requestAnimationFrame(frame)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
handle = window.requestAnimationFrame(frame)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
cancel,
|
|
33
|
+
schedule,
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/env.d.ts
ADDED
|
File without changes
|
package/src/increment.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { clamp } from './clamp'
|
|
2
|
+
|
|
3
|
+
export const increment = (progress: number): number => {
|
|
4
|
+
let amount = 0
|
|
5
|
+
|
|
6
|
+
if (progress >= 0 && progress < 0.2) {
|
|
7
|
+
amount = 0.1
|
|
8
|
+
} else if (progress >= 0.2 && progress < 0.5) {
|
|
9
|
+
amount = 0.04
|
|
10
|
+
} else if (progress >= 0.5 && progress < 0.8) {
|
|
11
|
+
amount = 0.02
|
|
12
|
+
} else if (progress >= 0.8 && progress < 0.99) {
|
|
13
|
+
amount = 0.005
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return clamp(progress + amount, 0, 0.994)
|
|
17
|
+
}
|
package/src/index.tsx
ADDED
package/src/types.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface NProgressOptions {
|
|
2
|
+
animationDuration?: number
|
|
3
|
+
increment?: (progress: number) => number
|
|
4
|
+
incrementDuration?: number
|
|
5
|
+
isAnimating?: boolean
|
|
6
|
+
minimum?: number
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface NProgressState {
|
|
10
|
+
animationDuration: number
|
|
11
|
+
isFinished: boolean
|
|
12
|
+
progress: number
|
|
13
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { useEffect, useReducer, useRef } from 'react'
|
|
2
|
+
|
|
3
|
+
import { clamp } from './clamp'
|
|
4
|
+
import { createTimeout } from './createTimeout'
|
|
5
|
+
import { increment as defaultIncrement } from './increment'
|
|
6
|
+
import type { NProgressOptions, NProgressState } from './types'
|
|
7
|
+
|
|
8
|
+
// A four-phase state machine. `idle` and `finished` both report
|
|
9
|
+
// `isFinished: true` and differ only in the progress they hold, so the phase,
|
|
10
|
+
// not `isFinished`, is what decides which transitions and timers apply.
|
|
11
|
+
type Phase = 'animating' | 'completing' | 'finished' | 'idle'
|
|
12
|
+
|
|
13
|
+
interface State {
|
|
14
|
+
phase: Phase
|
|
15
|
+
progress: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type Action =
|
|
19
|
+
| {
|
|
20
|
+
increment: (progress: number) => number
|
|
21
|
+
minimum: number
|
|
22
|
+
type: 'trickle'
|
|
23
|
+
}
|
|
24
|
+
| { minimum: number; type: 'start' }
|
|
25
|
+
| { type: 'complete' }
|
|
26
|
+
| { type: 'finish' }
|
|
27
|
+
|
|
28
|
+
const initialState: State = {
|
|
29
|
+
phase: 'idle',
|
|
30
|
+
progress: 0,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const reducer = (state: State, action: Action): State => {
|
|
34
|
+
switch (action.type) {
|
|
35
|
+
case 'complete':
|
|
36
|
+
// The original nprogress `done()` computes a random progress jump before
|
|
37
|
+
// animating to 1, but its queue runs both steps in the same tick, so the
|
|
38
|
+
// jump's CSS is overwritten before paint and never renders. Omitting the
|
|
39
|
+
// jump changes nothing visually.
|
|
40
|
+
//
|
|
41
|
+
// Ignored unless an animation is actually running, which is what makes a
|
|
42
|
+
// StrictMode double-mount a no-op rather than a spurious completion.
|
|
43
|
+
return state.phase === 'animating'
|
|
44
|
+
? { phase: 'completing', progress: 1 }
|
|
45
|
+
: state
|
|
46
|
+
|
|
47
|
+
case 'finish':
|
|
48
|
+
return { phase: 'finished', progress: 1 }
|
|
49
|
+
|
|
50
|
+
case 'start':
|
|
51
|
+
// Matches the original nprogress `start()`, which calls set(0) and so
|
|
52
|
+
// paints first at `minimum` before any trickle runs.
|
|
53
|
+
//
|
|
54
|
+
// Guarded the same way as `complete`, and for the same reason: a repeat
|
|
55
|
+
// dispatch against a running animation must not rewind the bar. That
|
|
56
|
+
// happens whenever `minimum` changes mid-animation, as well as on a
|
|
57
|
+
// StrictMode double-mount.
|
|
58
|
+
return state.phase === 'animating'
|
|
59
|
+
? state
|
|
60
|
+
: {
|
|
61
|
+
phase: 'animating',
|
|
62
|
+
progress: clamp(0, action.minimum, 1),
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
case 'trickle':
|
|
66
|
+
// Clamped here rather than trusted from the increment function, so a
|
|
67
|
+
// custom one cannot take the bar outside the documented range. Stopping
|
|
68
|
+
// short of 1 is that function's own business: 1 is what completion
|
|
69
|
+
// means.
|
|
70
|
+
return {
|
|
71
|
+
...state,
|
|
72
|
+
progress: clamp(action.increment(state.progress), action.minimum, 1),
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const useNProgress = ({
|
|
78
|
+
animationDuration = 200,
|
|
79
|
+
increment = defaultIncrement,
|
|
80
|
+
incrementDuration = 200,
|
|
81
|
+
isAnimating = false,
|
|
82
|
+
minimum = 0.08,
|
|
83
|
+
}: NProgressOptions = {}): NProgressState => {
|
|
84
|
+
const [{ phase, progress }, dispatch] = useReducer(reducer, initialState)
|
|
85
|
+
|
|
86
|
+
// Held in a ref so the trickle timer can read the latest increment function
|
|
87
|
+
// without listing it as a dependency. Consumers commonly pass an inline
|
|
88
|
+
// function, whose identity changes every render; depending on it directly
|
|
89
|
+
// would cancel and recreate the timer each time, and a render loop faster
|
|
90
|
+
// than `incrementDuration` would stop the bar advancing altogether.
|
|
91
|
+
const incrementRef = useRef(increment)
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
incrementRef.current = increment
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
dispatch(isAnimating ? { minimum, type: 'start' } : { type: 'complete' })
|
|
98
|
+
}, [isAnimating, minimum])
|
|
99
|
+
|
|
100
|
+
// A timer per running phase, rather than one effect branching over both.
|
|
101
|
+
// Each then depends only on the options its own phase reads, so changing an
|
|
102
|
+
// option the running phase ignores cannot cancel its timer. Both are keyed
|
|
103
|
+
// on the phase rather than on progress, so trickling does not tear down and
|
|
104
|
+
// recreate the timer mid-animation.
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
if (phase !== 'animating') {
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const timeout = createTimeout()
|
|
111
|
+
|
|
112
|
+
const trickle = () => {
|
|
113
|
+
dispatch({ increment: incrementRef.current, minimum, type: 'trickle' })
|
|
114
|
+
timeout.schedule(trickle, incrementDuration)
|
|
115
|
+
}
|
|
116
|
+
timeout.schedule(trickle, incrementDuration)
|
|
117
|
+
|
|
118
|
+
return () => timeout.cancel()
|
|
119
|
+
}, [incrementDuration, minimum, phase])
|
|
120
|
+
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
if (phase !== 'completing') {
|
|
123
|
+
return
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const timeout = createTimeout()
|
|
127
|
+
timeout.schedule(() => dispatch({ type: 'finish' }), animationDuration)
|
|
128
|
+
|
|
129
|
+
return () => timeout.cancel()
|
|
130
|
+
}, [animationDuration, phase])
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
animationDuration,
|
|
134
|
+
isFinished: phase === 'finished' || phase === 'idle',
|
|
135
|
+
progress,
|
|
136
|
+
}
|
|
137
|
+
}
|
package/dist/NProgress.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { FC, ReactElement } from 'react';
|
|
2
|
-
import type { Options } from './types';
|
|
3
|
-
import { useNProgress } from './useNProgress';
|
|
4
|
-
type Props = Options & {
|
|
5
|
-
children: (renderProps: ReturnType<typeof useNProgress>) => ReactElement;
|
|
6
|
-
};
|
|
7
|
-
export declare const NProgress: FC<Props>;
|
|
8
|
-
export {};
|
package/dist/clamp.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const clamp: (num: number, lower: number, upper: number) => number;
|
package/dist/createQueue.d.ts
DELETED
package/dist/createTimeout.d.ts
DELETED
package/dist/increment.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const increment: (progress: number) => number;
|
package/dist/index.d.ts
DELETED