├── .changeset ├── README.md └── config.json ├── .eslintrc.js ├── .github └── ISSUE_TEMPLATE │ ├── 1.bug_report.yml │ ├── 2.feature_request.yml │ └── config.yml ├── .gitignore ├── .husky └── pre-push ├── .npmrc ├── .prettierrc ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── apps ├── create-react-app │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── App.tsx │ │ ├── ProgressRouter.tsx │ │ ├── index.css │ │ ├── index.tsx │ │ └── react-app-env.d.ts │ └── tsconfig.json ├── docs │ ├── .eslintrc.json │ ├── .gitignore │ ├── app │ │ ├── (home) │ │ │ ├── _components │ │ │ │ ├── header.tsx │ │ │ │ └── hero.tsx │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ │ ├── api │ │ │ └── search │ │ │ │ └── route.ts │ │ ├── docs │ │ │ ├── [[...slug]] │ │ │ │ └── page.tsx │ │ │ └── layout.tsx │ │ ├── favicon.ico │ │ ├── globals.css │ │ ├── layout.config.tsx │ │ ├── layout.tsx │ │ ├── providers.tsx │ │ ├── robots.txt │ │ └── sitemap.ts │ ├── components.json │ ├── components │ │ ├── logo.tsx │ │ └── progress-type-table.tsx │ ├── content │ │ └── docs │ │ │ ├── configure.mdx │ │ │ ├── css.mdx │ │ │ ├── dec.mdx │ │ │ ├── done.mdx │ │ │ ├── get-positioning-css.mdx │ │ │ ├── inc.mdx │ │ │ ├── index.mdx │ │ │ ├── installation.mdx │ │ │ ├── is-rendered.mdx │ │ │ ├── is-started.mdx │ │ │ ├── meta.json │ │ │ ├── migration.mdx │ │ │ ├── next │ │ │ ├── components │ │ │ │ └── progress-provider.mdx │ │ │ ├── data-attributes │ │ │ │ ├── disable-progress.mdx │ │ │ │ ├── meta.json │ │ │ │ └── prevent-progress.mdx │ │ │ ├── hooks │ │ │ │ └── use-router.mdx │ │ │ ├── installation.mdx │ │ │ ├── meta.json │ │ │ ├── migration.mdx │ │ │ ├── quick-start.mdx │ │ │ └── whats-new.mdx │ │ │ ├── other-projects.mdx │ │ │ ├── pause.mdx │ │ │ ├── promise.mdx │ │ │ ├── quick-start.mdx │ │ │ ├── react │ │ │ ├── components │ │ │ │ ├── progress-components │ │ │ │ │ ├── bar.mdx │ │ │ │ │ ├── indeterminate.mdx │ │ │ │ │ ├── meta.json │ │ │ │ │ ├── peg.mdx │ │ │ │ │ ├── progress.mdx │ │ │ │ │ ├── spinner-icon.mdx │ │ │ │ │ └── spinner.mdx │ │ │ │ └── progress-provider.mdx │ │ │ ├── hooks │ │ │ │ ├── use-anchor-progress.mdx │ │ │ │ └── use-progress.mdx │ │ │ ├── installation.mdx │ │ │ ├── meta.json │ │ │ ├── quick-start.mdx │ │ │ └── utils │ │ │ │ ├── with-memo.mdx │ │ │ │ └── with-suspense.mdx │ │ │ ├── remix │ │ │ ├── data-attributes │ │ │ │ ├── disable-progress.mdx │ │ │ │ ├── meta.json │ │ │ │ └── prevent-progress.mdx │ │ │ ├── hooks │ │ │ │ └── use-navigate.mdx │ │ │ ├── installation.mdx │ │ │ ├── meta.json │ │ │ └── quick-start.mdx │ │ │ ├── remove.mdx │ │ │ ├── render.mdx │ │ │ ├── reset.mdx │ │ │ ├── resume.mdx │ │ │ ├── roadmap.mdx │ │ │ ├── same-url.mdx │ │ │ ├── set.mdx │ │ │ ├── start.mdx │ │ │ ├── style.mdx │ │ │ ├── trickle.mdx │ │ │ ├── upgrade.mdx │ │ │ └── vue │ │ │ ├── components │ │ │ ├── progress-components │ │ │ │ ├── bar.mdx │ │ │ │ ├── indeterminate.mdx │ │ │ │ ├── meta.json │ │ │ │ ├── peg.mdx │ │ │ │ ├── progress.mdx │ │ │ │ ├── spinner-icon.mdx │ │ │ │ └── spinner.mdx │ │ │ └── progress-provider.mdx │ │ │ ├── composables │ │ │ ├── use-anchor-progress.mdx │ │ │ └── use-progress.mdx │ │ │ ├── installation.mdx │ │ │ ├── meta.json │ │ │ └── quick-start.mdx │ ├── lib │ │ └── source.ts │ ├── next.config.mjs │ ├── package.json │ ├── postcss.config.mjs │ ├── public │ │ └── animate-ui.mp4 │ ├── site.config.ts │ ├── source.config.ts │ ├── tailwind.config.ts │ └── tsconfig.json ├── html │ ├── index.css │ ├── index.esm.html │ └── index.html ├── next-app-dir │ ├── .gitignore │ ├── __tests__ │ │ ├── e2e │ │ │ └── example.spec.ts │ │ └── unit │ │ │ └── home.test.tsx │ ├── app │ │ └── [locale] │ │ │ ├── dashboard │ │ │ └── page.tsx │ │ │ ├── docs │ │ │ └── page.tsx │ │ │ ├── favicon.ico │ │ │ ├── globals.css │ │ │ ├── layout.tsx │ │ │ ├── load │ │ │ └── page.tsx │ │ │ ├── mounted │ │ │ └── page.tsx │ │ │ ├── page.tsx │ │ │ └── providers.tsx │ ├── eslint.config.js │ ├── i18n │ │ ├── navigation.ts │ │ ├── request.ts │ │ └── routing.ts │ ├── jest.config.ts │ ├── jest.setup.ts │ ├── messages │ │ ├── en.json │ │ └── fr.json │ ├── middleware.ts │ ├── next-env.d.ts │ ├── next.config.mjs │ ├── package.json │ ├── playwright.config.ts │ ├── postcss.config.mjs │ ├── tailwind.config.ts │ └── tsconfig.json ├── pages-app-dir │ ├── eslint.config.js │ ├── globals.css │ ├── next-env.d.ts │ ├── next.config.mjs │ ├── package.json │ ├── pages │ │ ├── _app.tsx │ │ ├── _document.tsx │ │ ├── dashboard.tsx │ │ └── index.tsx │ ├── postcss.config.mjs │ ├── tailwind.config.ts │ └── tsconfig.json ├── remix-app │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── app │ │ ├── entry.client.tsx │ │ ├── entry.server.tsx │ │ ├── root.tsx │ │ ├── routes │ │ │ ├── _index.tsx │ │ │ ├── dashboard.tsx │ │ │ └── profile.tsx │ │ └── tailwind.css │ ├── package.json │ ├── postcss.config.js │ ├── public │ │ ├── favicon.ico │ │ ├── logo-dark.png │ │ └── logo-light.png │ ├── tailwind.config.ts │ ├── tsconfig.json │ └── vite.config.ts └── vue-app │ ├── .editorconfig │ ├── .gitattributes │ ├── .gitignore │ ├── .prettierrc.json │ ├── .vscode │ └── extensions.json │ ├── README.md │ ├── env.d.ts │ ├── eslint.config.ts │ ├── index.html │ ├── package.json │ ├── public │ └── favicon.ico │ ├── src │ ├── App.vue │ ├── Root.vue │ ├── assets │ │ ├── base.css │ │ ├── logo.svg │ │ └── main.css │ ├── components │ │ ├── HelloWorld.vue │ │ ├── ProgressBar.vue │ │ ├── TheWelcome.vue │ │ ├── WelcomeItem.vue │ │ └── icons │ │ │ ├── IconCommunity.vue │ │ │ ├── IconDocumentation.vue │ │ │ ├── IconEcosystem.vue │ │ │ ├── IconSupport.vue │ │ │ └── IconTooling.vue │ ├── main.ts │ ├── router │ │ └── index.ts │ └── views │ │ ├── AboutView.vue │ │ └── HomeView.vue │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── package.json ├── packages ├── core │ ├── .gitignore │ ├── .npmignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── __tests__ │ │ ├── get-anchor-property.test.ts │ │ ├── lib.test.ts │ │ ├── progress.test.ts │ │ └── utils.test.ts │ ├── eslint.config.js │ ├── jest.config.ts │ ├── package.json │ ├── src │ │ ├── index.css │ │ ├── index.ts │ │ ├── lib │ │ │ ├── css.ts │ │ │ ├── get-anchor-property.ts │ │ │ ├── index.ts │ │ │ └── same-url.ts │ │ ├── progress.ts │ │ ├── types.ts │ │ └── utils │ │ │ ├── clamp.ts │ │ │ ├── class.ts │ │ │ ├── element.ts │ │ │ ├── index.ts │ │ │ ├── to-bar-perc.ts │ │ │ └── to-css.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── eslint-config │ ├── README.md │ ├── base.js │ ├── next.js │ ├── package.json │ ├── react-internal.js │ └── vue.js ├── next │ ├── .gitignore │ ├── .npmignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── eslint.config.js │ ├── package.json │ ├── src │ │ ├── app.ts │ │ ├── components │ │ │ ├── app-progress.tsx │ │ │ └── pages-progress.tsx │ │ ├── hooks │ │ │ └── use-router.ts │ │ ├── index.ts │ │ ├── pages.ts │ │ ├── providers │ │ │ ├── app-progress-provider.tsx │ │ │ ├── next-progress-provider.tsx │ │ │ └── pages-progress-provider.tsx │ │ └── types.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── react │ ├── .gitignore │ ├── .npmignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── __tests__ │ │ ├── components │ │ │ ├── bar.test.tsx │ │ │ ├── indeterminate.test.tsx │ │ │ ├── peg.test.tsx │ │ │ ├── progress.test.tsx │ │ │ ├── spinner-icon.test.tsx │ │ │ └── spinner.test.tsx │ │ ├── hooks │ │ │ └── use-anchor-progress.test.tsx │ │ ├── providers │ │ │ └── progress-provider.test.tsx │ │ └── utils │ │ │ ├── classnames.test.ts │ │ │ ├── with-memo.test.tsx │ │ │ └── with-suspense.test.tsx │ ├── eslint.config.js │ ├── jest.config.ts │ ├── jest.setup.ts │ ├── package.json │ ├── src │ │ ├── components │ │ │ ├── bar.tsx │ │ │ ├── indeterminate.tsx │ │ │ ├── index.tsx │ │ │ ├── peg.tsx │ │ │ ├── progress.tsx │ │ │ ├── spinner-icon.tsx │ │ │ └── spinner.tsx │ │ ├── hooks │ │ │ └── use-anchor-progress.tsx │ │ ├── index.tsx │ │ ├── providers │ │ │ └── progress-provider.tsx │ │ ├── types.ts │ │ └── utils │ │ │ ├── classnames.ts │ │ │ ├── index.ts │ │ │ ├── with-memo.tsx │ │ │ └── with-suspense.tsx │ ├── tsconfig.json │ └── tsup.config.ts ├── remix │ ├── .gitignore │ ├── .npmignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── eslint.config.js │ ├── package.json │ ├── src │ │ ├── components │ │ │ └── remix-progress.tsx │ │ ├── hooks │ │ │ └── use-navigate.tsx │ │ ├── index.tsx │ │ ├── providers │ │ │ └── remix-progress-provider.tsx │ │ └── types.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── typescript-config │ ├── README.md │ ├── base.json │ ├── nextjs.json │ ├── package.json │ └── react-library.json ├── ui │ ├── components.json │ ├── eslint.config.js │ ├── package.json │ ├── postcss.config.mjs │ ├── src │ │ ├── components │ │ │ └── ui │ │ │ │ ├── background-lines.tsx │ │ │ │ ├── button.tsx │ │ │ │ ├── hero-highlight.tsx │ │ │ │ └── theme-switcher.tsx │ │ ├── lib │ │ │ └── utils.ts │ │ └── styles │ │ │ └── globals.css │ ├── tailwind.config.ts │ ├── tsconfig.json │ └── tsconfig.lint.json └── vue │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── __tests__ │ ├── components │ │ ├── bar.test.ts │ │ ├── indeterminate.test.ts │ │ ├── peg.test.ts │ │ ├── progress.test.ts │ │ ├── spinner-icon.test.ts │ │ └── spinner.test.ts │ ├── composables │ │ └── use-anchor-progress.test.ts │ ├── providers │ │ └── progress-provider.test.ts │ └── utils │ │ └── classnames.test.ts │ ├── eslint.config.js │ ├── jest.config.ts │ ├── jest.setup.ts │ ├── package.json │ ├── shims-vue.d.ts │ ├── src │ ├── components │ │ ├── bar.vue │ │ ├── indeterminate.vue │ │ ├── index.ts │ │ ├── peg.vue │ │ ├── progress.vue │ │ ├── spinner-icon.vue │ │ └── spinner.vue │ ├── composables │ │ ├── index.ts │ │ ├── use-anchor-progress.ts │ │ └── use-progress.ts │ ├── index.ts │ ├── providers │ │ └── progress-provider.vue │ ├── types.ts │ └── utils │ │ └── classnames.ts │ ├── tsconfig.json │ ├── vite.config.ts │ └── vue3JestHack.js ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── tsconfig.json └── turbo.json /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "restricted", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [ 11 | "next-app-dir", 12 | "pages-app-dir", 13 | "docs", 14 | "create-react-app", 15 | "remix-app" 16 | ], 17 | "publish": false, 18 | "version": { 19 | "mode": "independent" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // This configuration only applies to the package manager root. 2 | /** @type {import("eslint").Linter.Config} */ 3 | module.exports = { 4 | ignorePatterns: ["apps/**", "packages/**"], 5 | extends: ["@workspace/eslint-config/library.js"], 6 | parser: "@typescript-eslint/parser", 7 | parserOptions: { 8 | project: true, 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1.bug_report.yml: -------------------------------------------------------------------------------- 1 | name: 🐞 Bug report 2 | description: Report a bug with BProgress packages or docs. 3 | labels: ['bug'] 4 | body: 5 | - type: textarea 6 | attributes: 7 | label: Description 8 | description: A detailed description of the issue that you are encountering, and how other people can reproduce it. This includes useful information such as the framework you use, how you use BProgress, etc. 9 | placeholder: | 10 | Reproduction steps... 11 | validations: 12 | required: true 13 | - type: textarea 14 | attributes: 15 | label: Code example 16 | description: Provide an example code snippet that has the problem. 17 | placeholder: | 18 | import '@bprogress/core/css'; 19 | import { BProgress } from '@bprogress/core'; 20 | ... 21 | - type: input 22 | id: provider 23 | attributes: 24 | label: Package used (or docs) 25 | description: The package (e.g. `@bprogress/core`) that you are using, and its version (e.g. `1.0.0`). 26 | placeholder: | 27 | @bprogress/core v1.0.0 28 | - type: textarea 29 | attributes: 30 | label: Additional context 31 | description: | 32 | Any extra information that might help us investigate. 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2.feature_request.yml: -------------------------------------------------------------------------------- 1 | name: ✨ Feature Request 2 | description: Propose a new feature for BProgress. 3 | labels: ['enhancement'] 4 | body: 5 | - type: textarea 6 | attributes: 7 | label: Feature Description 8 | description: A detailed description of the feature you are proposing. 9 | placeholder: | 10 | Feature description... 11 | validations: 12 | required: true 13 | - type: textarea 14 | attributes: 15 | label: Use Cases 16 | description: Provide use cases where this feature would be beneficial. 17 | placeholder: | 18 | Use case... 19 | - type: input 20 | id: provider 21 | attributes: 22 | label: Package 23 | description: The package (e.g. `@bprogress/core`) concerned by the feature 24 | placeholder: | 25 | @bprogress/core 26 | - type: textarea 27 | attributes: 28 | label: Additional context 29 | description: | 30 | Any extra information that might help us understand your feature request. 31 | placeholder: | 32 | Additional context... 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: 💬 Ask a question 4 | url: https://github.com/imskyleen/bprogress/discussions 5 | about: Please ask questions in our discussions forum. 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # Dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # Local env files 9 | .env 10 | .env.local 11 | .env.development.local 12 | .env.test.local 13 | .env.production.local 14 | 15 | # Testing 16 | coverage 17 | 18 | # Turbo 19 | .turbo 20 | 21 | # Vercel 22 | .vercel 23 | 24 | # Build Outputs 25 | .next/ 26 | out/ 27 | build 28 | dist 29 | 30 | 31 | # Debug 32 | npm-debug.log* 33 | 34 | # Misc 35 | .DS_Store 36 | *.pem 37 | -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | pnpm lint && pnpm test && pnpm build 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imskyleen/bprogress/f3c776a8d00cbcd55017439bf8a5053f9dbc0976/.npmrc -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "tabWidth": 2, 4 | "semi": true, 5 | "singleQuote": true 6 | } 7 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "liveServer.settings.port": 5502 3 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Elliot Sutton 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /apps/create-react-app/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /apps/create-react-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-react-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@types/node": "^16.18.126", 7 | "@types/react": "^19.0.1", 8 | "@types/react-dom": "^19.0.2", 9 | "react": "^19.0.0", 10 | "react-dom": "^19.0.0", 11 | "react-scripts": "5.0.1", 12 | "typescript": "^4.9.5", 13 | "web-vitals": "^2.1.4", 14 | "@bprogress/react": "workspace:*" 15 | }, 16 | "scripts": { 17 | "start": "DISABLE_ESLINT_PLUGIN=true react-scripts start", 18 | "eject": "react-scripts eject" 19 | }, 20 | "eslintConfig": { 21 | "extends": [ 22 | "react-app", 23 | "react-app/jest" 24 | ] 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /apps/create-react-app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imskyleen/bprogress/f3c776a8d00cbcd55017439bf8a5053f9dbc0976/apps/create-react-app/public/favicon.ico -------------------------------------------------------------------------------- /apps/create-react-app/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /apps/create-react-app/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imskyleen/bprogress/f3c776a8d00cbcd55017439bf8a5053f9dbc0976/apps/create-react-app/public/logo192.png -------------------------------------------------------------------------------- /apps/create-react-app/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imskyleen/bprogress/f3c776a8d00cbcd55017439bf8a5053f9dbc0976/apps/create-react-app/public/logo512.png -------------------------------------------------------------------------------- /apps/create-react-app/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /apps/create-react-app/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /apps/create-react-app/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useProgress } from '@bprogress/react'; 2 | 3 | function App() { 4 | const { start, stop, pause, resume } = useProgress(); 5 | 6 | return ( 7 |
8 |

React BProgress

9 | 10 | 11 | 12 | 13 | 14 | 22 | 30 |
31 | ); 32 | } 33 | 34 | export default App; 35 | -------------------------------------------------------------------------------- /apps/create-react-app/src/ProgressRouter.tsx: -------------------------------------------------------------------------------- 1 | import { useAnchorProgress } from '@bprogress/react'; 2 | 3 | export const ProgressRouter = () => { 4 | useAnchorProgress( 5 | { 6 | forcedStopDelay: 500, 7 | }, 8 | [], 9 | ); 10 | 11 | return null; 12 | }; 13 | -------------------------------------------------------------------------------- /apps/create-react-app/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /apps/create-react-app/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import { ProgressProvider } from '@bprogress/react'; 6 | import { ProgressRouter } from './ProgressRouter'; 7 | 8 | const root = ReactDOM.createRoot( 9 | document.getElementById('root') as HTMLElement, 10 | ); 11 | root.render( 12 | 13 | 14 | 15 | 16 | 17 | , 18 | ); 19 | -------------------------------------------------------------------------------- /apps/create-react-app/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/create-react-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /apps/docs/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["next/core-web-vitals", "next/typescript"] 3 | } 4 | -------------------------------------------------------------------------------- /apps/docs/.gitignore: -------------------------------------------------------------------------------- 1 | # deps 2 | /node_modules 3 | 4 | # generated content 5 | .contentlayer 6 | .content-collections 7 | .source 8 | 9 | # test & build 10 | /coverage 11 | /.next/ 12 | /out/ 13 | /build 14 | *.tsbuildinfo 15 | 16 | # misc 17 | .DS_Store 18 | *.pem 19 | /.pnp 20 | .pnp.js 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | # others 26 | .env*.local 27 | .vercel 28 | next-env.d.ts -------------------------------------------------------------------------------- /apps/docs/app/(home)/layout.tsx: -------------------------------------------------------------------------------- 1 | export default function Layout({ children }: { children: React.ReactNode }) { 2 | return children; 3 | } 4 | -------------------------------------------------------------------------------- /apps/docs/app/(home)/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { Hero } from './_components/hero'; 4 | import { Header } from './_components/header'; 5 | import { BackgroundLines } from '@workspace/ui/components/ui/background-lines'; 6 | 7 | export default function HomePage() { 8 | return ( 9 |
10 |
11 | 12 | 13 | 14 | 15 |
16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /apps/docs/app/api/search/route.ts: -------------------------------------------------------------------------------- 1 | import { source } from '@/lib/source'; 2 | import { createFromSource } from 'fumadocs-core/search/server'; 3 | 4 | export const { GET } = createFromSource(source); 5 | -------------------------------------------------------------------------------- /apps/docs/app/docs/[[...slug]]/page.tsx: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | 3 | import { source } from '@/lib/source'; 4 | import { 5 | DocsPage, 6 | DocsBody, 7 | DocsDescription, 8 | DocsTitle, 9 | } from 'fumadocs-ui/page'; 10 | import { notFound } from 'next/navigation'; 11 | import defaultMdxComponents from 'fumadocs-ui/mdx'; 12 | 13 | export default async function Page(props: { 14 | params: Promise<{ slug?: string[] }>; 15 | }) { 16 | const params = await props.params; 17 | const page = source.getPage(params.slug); 18 | if (!page) notFound(); 19 | 20 | const MDX = page.data.body; 21 | 22 | return ( 23 | 24 | {page.data.title} 25 | {page.data.description} 26 | 27 | 28 | 29 | 30 | ); 31 | } 32 | 33 | export async function generateStaticParams() { 34 | return source.generateParams(); 35 | } 36 | 37 | export async function generateMetadata(props: { 38 | params: Promise<{ slug?: string[] }>; 39 | }) { 40 | const params = await props.params; 41 | const page = source.getPage(params.slug); 42 | if (!page) notFound(); 43 | 44 | return { 45 | title: page.data.title, 46 | description: page.data.description, 47 | }; 48 | } 49 | -------------------------------------------------------------------------------- /apps/docs/app/docs/layout.tsx: -------------------------------------------------------------------------------- 1 | import { DocsLayout } from 'fumadocs-ui/layouts/docs'; 2 | import { baseOptions } from '@/app/layout.config'; 3 | import { source } from '@/lib/source'; 4 | 5 | export default function Layout({ children }: { children: React.ReactNode }) { 6 | return ( 7 | 12 | {children} 13 | 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /apps/docs/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imskyleen/bprogress/f3c776a8d00cbcd55017439bf8a5053f9dbc0976/apps/docs/app/favicon.ico -------------------------------------------------------------------------------- /apps/docs/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | .code-block pre { 6 | @apply !bg-transparent !p-0; 7 | } 8 | 9 | .code-block pre code { 10 | @apply !bg-transparent; 11 | } 12 | 13 | .npm-button path { 14 | @apply !fill-white; 15 | } 16 | 17 | .bprogress-logo { 18 | display: inline-block; 19 | width: 70%; 20 | max-width: 300px; 21 | height: 40px; 22 | border: solid 4px currentColor; 23 | border-radius: 999px; 24 | position: relative; 25 | margin-bottom: 10px; 26 | } 27 | 28 | .bprogress-logo:after { 29 | content: ""; 30 | display: block; 31 | position: absolute; 32 | top: 4px; 33 | left: 4px; 34 | bottom: 4px; 35 | background: currentColor; 36 | border-radius: 999px; 37 | animation: progress 14s infinite; 38 | } 39 | 40 | .fade { 41 | transition: all 300ms linear 700ms; 42 | -webkit-transform: translate3d(0,0,0); 43 | -moz-transform: translate3d(0,0,0); 44 | -ms-transform: translate3d(0,0,0); 45 | -o-transform: translate3d(0,0,0); 46 | transform: translate3d(0,0,0); 47 | opacity: 1; 48 | } 49 | 50 | @keyframes progress { 51 | 0% { 52 | width: 5%; 53 | } 54 | 250% { 55 | width: 40%; 56 | } 57 | 50% { 58 | width: 95%; 59 | } 60 | 75% { 61 | width: 60%; 62 | } 63 | 100% { 64 | width: 5%; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /apps/docs/app/layout.config.tsx: -------------------------------------------------------------------------------- 1 | import { Logo } from '@/components/logo'; 2 | import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared'; 3 | 4 | /** 5 | * Shared layout configurations 6 | * 7 | * you can configure layouts individually from: 8 | * Home Layout: app/(home)/layout.tsx 9 | * Docs Layout: app/docs/layout.tsx 10 | */ 11 | export const baseOptions: BaseLayoutProps = { 12 | nav: { 13 | title: , 14 | }, 15 | links: [ 16 | { 17 | text: 'Documentation', 18 | url: '/docs', 19 | active: 'nested-url', 20 | }, 21 | ], 22 | }; 23 | -------------------------------------------------------------------------------- /apps/docs/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import '@workspace/ui/globals.css'; 2 | import './globals.css'; 3 | 4 | import { RootProvider } from 'fumadocs-ui/provider'; 5 | import { Inter } from 'next/font/google'; 6 | import Providers from './providers'; 7 | 8 | const inter = Inter({ 9 | subsets: ['latin'], 10 | }); 11 | 12 | export const metadata = { 13 | title: 'BProgress - Lightweight progress bar', 14 | description: 15 | 'A lightweight and customizable progress bar for better user experience.', 16 | keywords: [ 17 | 'next', 18 | 'next.js', 19 | 'progress', 20 | 'progress bar', 21 | 'nprogress', 22 | 'bprogress', 23 | 'next-progress', 24 | 'next-nprogress', 25 | 'next-nprogress-bar', 26 | 'nprogress-v2', 27 | '@bprogress/core', 28 | '@bprogress/next', 29 | ], 30 | }; 31 | 32 | export default function Layout({ children }: { children: React.ReactNode }) { 33 | return ( 34 | 35 | 36 | 40 | 41 | 42 | 43 | 44 | 49 | {children} 50 | 51 | 52 | 53 | 54 | ); 55 | } 56 | -------------------------------------------------------------------------------- /apps/docs/app/providers.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { AppProgressProvider as ProgressProvider } from '@bprogress/next'; 4 | 5 | const Providers = ({ children }: { children: React.ReactNode }) => { 6 | return ( 7 | 13 | {children} 14 | 15 | ); 16 | }; 17 | 18 | export default Providers; 19 | -------------------------------------------------------------------------------- /apps/docs/app/robots.txt: -------------------------------------------------------------------------------- 1 | User-Agent: * 2 | Allow: / 3 | 4 | Sitemap: https://bprogress.vercel.app/sitemap.xml 5 | -------------------------------------------------------------------------------- /apps/docs/app/sitemap.ts: -------------------------------------------------------------------------------- 1 | import { source } from '@/lib/source'; 2 | import type { MetadataRoute } from 'next'; 3 | 4 | export default async function sitemap(): Promise { 5 | return [ 6 | { 7 | url: 'https://bprogress.vercel.app', 8 | lastModified: new Date().toISOString(), 9 | }, 10 | ...source.getPages().map((page) => ({ 11 | url: `https://bprogress.vercel.app${page.url}`, 12 | lastModified: new Date().toISOString(), 13 | })), 14 | ]; 15 | } 16 | -------------------------------------------------------------------------------- /apps/docs/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "../../packages/ui/tailwind.config.ts", 8 | "css": "../../packages/ui/src/styles/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true 11 | }, 12 | "iconLibrary": "lucide", 13 | "aliases": { 14 | "components": "@/components", 15 | "hooks": "@/hooks", 16 | "lib": "@/lib", 17 | "utils": "@workspace/ui/lib/utils", 18 | "ui": "@workspace/ui/components" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /apps/docs/content/docs/css.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: CSS 3 | description: Returns css classes in string 4 | --- 5 | 6 | ## `css()` 7 | 8 | ### Import 9 | 10 | ```ts 11 | import { css } from '@bprogress/react'; 12 | ``` 13 | 14 | ### Type 15 | 16 | ```ts 17 | function css(options: CssOptions): string; 18 | ``` 19 | 20 | #### `CssOptions` 21 | 22 | | Name | Type | Description | 23 | | ---- | ---- | ----------- | 24 | | `color` | `string` | Color of the text | 25 | | `height` | `string` | Height of the element | 26 | | `spinnerPosition` | `SpinnerPosition` | Position of the spinner | 27 | 28 | #### `SpinnerPosition` 29 | 30 | | Name | Description | 31 | | ---- | ----------- | 32 | | `top-left` | Spinner at the top left | 33 | | `top-right` | Spinner at the top right | 34 | | `bottom-left` | Spinner at the bottom left | 35 | | `bottom-right` | Spinner at the bottom right | 36 | 37 | -------------------------------------------------------------------------------- /apps/docs/content/docs/dec.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: dec() 3 | description: BProgress.dec() method 4 | --- 5 | 6 | The `dec()` method is used to decrement the progress bar by a specific percentage. 7 | 8 | ## Usage 9 | 10 | ```js 11 | BProgress.dec(0.2); 12 | ``` 13 | 14 | ## Typing 15 | 16 | ```ts 17 | BProgress.dec(amount: number): BProgress; 18 | ``` 19 | 20 | ## Parameters 21 | 22 | | Name | Type | Description | 23 | |--------|--------|----------------------| 24 | | amount | number | The percentage value between 0 and 1 | 25 | -------------------------------------------------------------------------------- /apps/docs/content/docs/done.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: done() 3 | description: BProgress.done() method 4 | --- 5 | 6 | The `done()` method is used to stop the progress bar. 7 | 8 | ## Usage 9 | 10 | ```js 11 | BProgress.done(); 12 | ``` 13 | 14 | ## Typing 15 | 16 | ```ts 17 | BProgress.done(force?: boolean): BProgress; 18 | ``` 19 | 20 | ## Parameters 21 | 22 | | Name | Type | Description | 23 | |-------|---------|--------------------------------------------------------------------| 24 | | force | boolean | Force the progress bar to finish immediately, even if not started. | 25 | -------------------------------------------------------------------------------- /apps/docs/content/docs/get-positioning-css.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: getPositioningCSS() 3 | description: BProgress.getPositioningCSS() method 4 | --- 5 | 6 | The `getPositioningCSS()` method determines which CSS transform approach is supported by the current browser (`translate3d`, `translate`, `margin`, or `width`). 7 | 8 | ## Usage 9 | 10 | ```js 11 | BProgress.getPositioningCSS(); 12 | ``` 13 | 14 | ## Typing 15 | 16 | ```ts 17 | BProgress.getPositioningCSS(): "translate3d" | "translate" | "margin" | "width"; 18 | ``` 19 | -------------------------------------------------------------------------------- /apps/docs/content/docs/inc.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: inc() 3 | description: BProgress.inc() method 4 | --- 5 | 6 | The `inc()` method is used to increment the progress bar by a specific percentage. 7 | 8 | ## Usage 9 | 10 | ```js 11 | BProgress.inc(0.2); 12 | ``` 13 | 14 | ## Typing 15 | 16 | ```ts 17 | BProgress.inc(amount: number): BProgress; 18 | ``` 19 | 20 | ## Parameters 21 | 22 | | Name | Type | Description | 23 | |--------|--------|----------------------| 24 | | amount | number | The percentage value between 0 and 1 | 25 | -------------------------------------------------------------------------------- /apps/docs/content/docs/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction 3 | description: What is BProgress? 4 | --- 5 | 6 | **BProgress** is built on the foundation of **NProgress**, a widely used progress bar library. However, **NProgress hasn't been maintained for over five years**, and its JavaScript codebase is outdated. Over time, many developers have submitted **issues and pull requests** requesting new features and improvements, but these have remained unaddressed. 7 | 8 | The name **BProgress** stands for **"Bar Progress"**, reflecting its purpose while allowing for future improvements and a more flexible evolution of the library. 9 | 10 | **BProgress is a modern reimplementation of NProgress**, fully rewritten in **TypeScript** with a clean and optimized syntax. It retains the simplicity of NProgress while introducing **modern best practices, active maintenance, and new features** that were missing from the original library. These improvements include **better customization, enhanced performance, and additional options requested by the community**. 11 | 12 | Our goal with BProgress is to **make progress bars easy to integrate across multiple frameworks**. We're building dedicated packages to ensure **seamless, efficient, and flexible** progress bar integration, no matter what framework you're using. 🚀 13 | 14 | ## Why is BProgress useful? 15 | 16 | **BProgress** is a lightweight progress bar designed to visually indicate loading states in web applications. It is commonly used to display a **smooth, animated progress bar** during **page transitions, data loading, or asynchronous operations**. 17 | 18 | It helps users understand that a new page or content is being loaded, making navigation more intuitive and preventing confusion during transitions. 19 | -------------------------------------------------------------------------------- /apps/docs/content/docs/is-rendered.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: isRendered() 3 | description: BProgress.isRendered() method 4 | --- 5 | 6 | The `isRendered()` method is used to check if the progress bar is rendered. 7 | 8 | ## Usage 9 | 10 | ```js 11 | BProgress.isRendered(); 12 | ``` 13 | 14 | ## Typing 15 | 16 | ```ts 17 | BProgress.isRendered(): boolean; 18 | ``` 19 | -------------------------------------------------------------------------------- /apps/docs/content/docs/is-started.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: isStarted() 3 | description: BProgress.isStarted() method 4 | --- 5 | 6 | The `isStarted()` method is used to check if the progress bar is started. 7 | 8 | ## Usage 9 | 10 | ```js 11 | BProgress.isStarted(); 12 | ``` 13 | 14 | ## Typing 15 | 16 | ```ts 17 | BProgress.isStarted(): boolean; 18 | ``` 19 | -------------------------------------------------------------------------------- /apps/docs/content/docs/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "BProgress", 3 | "root": true, 4 | "pages": [ 5 | "---Guide---", 6 | "index", 7 | "installation", 8 | "quick-start", 9 | "migration", 10 | "upgrade", 11 | "---Methods---", 12 | "configure", 13 | "reset", 14 | "start", 15 | "is-started", 16 | "done", 17 | "set", 18 | "inc", 19 | "dec", 20 | "trickle", 21 | "promise", 22 | "render", 23 | "remove", 24 | "pause", 25 | "resume", 26 | "is-rendered", 27 | "get-positioning-css", 28 | "---Style---", 29 | "style", 30 | "---Utils---", 31 | "css", 32 | "same-url", 33 | "---Integrations---", 34 | "react", 35 | "next", 36 | "remix", 37 | "vue", 38 | "---More---", 39 | "roadmap", 40 | "other-projects" 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /apps/docs/content/docs/next/components/progress-provider.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: ProgressProvider 3 | description: How to use ProgressProvider 4 | --- 5 | 6 | import { ProgressTypeTable } from '../../../../components/progress-type-table'; 7 | import { SiCsswizardry, SiNextdotjs } from 'react-icons/si'; 8 | 9 | Import the correct `ProgressProvider` according to your Next.js configuration. 10 | 11 | ## Import 12 | 13 | ```tsx 14 | // App Directory 15 | import { ProgressProvider } from '@bprogress/next/app'; 16 | 17 | // Pages Directory 18 | import { ProgressProvider } from '@bprogress/next/pages'; 19 | ``` 20 | 21 | ## Usage 22 | 23 | ```tsx 24 | ... 25 | ``` 26 | 27 | ## Props 28 | 29 | ### Common props 30 | 31 | 50 | 51 | ### AppProgressBar props 52 | 53 | 56 | 57 | ### Links 58 | 59 | 60 | } 63 | title="BProgress CSS" 64 | href="https://github.com/imskyleen/bprogress/blob/main/packages/core/index.css" 65 | description="Default BProgress CSS" 66 | /> 67 | } 70 | title="Next.js docs" 71 | href="https://nextjs.org/docs/pages/building-your-application/routing/linking-and-navigating#shallow-routing" 72 | description="Shallow routing on Next.js" 73 | /> 74 | 75 | -------------------------------------------------------------------------------- /apps/docs/content/docs/next/data-attributes/disable-progress.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Disable progress 3 | description: Disable the progress bar on specific links 4 | --- 5 | 6 | import { Callout } from 'fumadocs-ui/components/callout'; 7 | 8 | You can disable the progress bar on specific links by adding the `data-disable-progress={true}` attribute. 9 | 10 | 11 | This will not work for Link in svg elements. 12 | 13 | 14 | ## Usage 15 | 16 | ```tsx 17 | 18 | Features 19 | 20 | ``` 21 | 22 | 23 | This functionnality is only available for the app directory. 24 | 25 | -------------------------------------------------------------------------------- /apps/docs/content/docs/next/data-attributes/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Data Attributes (app dir)", 3 | "root": false, 4 | "pages": ["disable-progress", "prevent-progress"] 5 | } 6 | -------------------------------------------------------------------------------- /apps/docs/content/docs/next/data-attributes/prevent-progress.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Prevent progress 3 | description: Prevent the progress bar from starting 4 | --- 5 | 6 | import { Callout } from 'fumadocs-ui/components/callout'; 7 | 8 | You can prevent the progress bar from starting by adding the `data-prevent-progress={true}` attribute. 9 | 10 | ## Usage 11 | 12 | ```tsx 13 | 14 | Dashboard 15 | e.preventDefault()} data-prevent-progress={true}> 16 | preventDefault 17 | 18 | 19 | ``` 20 | 21 | 22 | This functionnality is only available for the app directory. 23 | 24 | -------------------------------------------------------------------------------- /apps/docs/content/docs/next/installation.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation 3 | description: Install BProgress in your Next.js application 4 | --- 5 | 6 | import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; 7 | import { SiNpm } from 'react-icons/si'; 8 | import { FaGithub } from 'react-icons/fa6'; 9 | 10 | ## Installation 11 | 12 | To install BProgress, run the following command: 13 | 14 | 15 | ```bash npm install @bprogress/next ``` 16 | ```bash pnpm add @bprogress/next ``` 17 | ```bash yarn add @bprogress/next ``` 18 | ```bash bun add @bprogress/next ``` 19 | 20 | 21 | Now you are ready to use BProgress in your Next.js application! 22 | 23 | ## Links 24 | 25 | 26 | } 31 | > 32 | Check the package on NPM 33 | 34 | } 39 | > 40 | Check the repository on GitHub 41 | 42 | 43 | -------------------------------------------------------------------------------- /apps/docs/content/docs/next/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Next.js", 3 | "root": false, 4 | "pages": [ 5 | "---Guide---", 6 | "installation", 7 | "quick-start", 8 | "migration", 9 | "whats-new", 10 | "---Components---", 11 | "components/progress-provider", 12 | "../react/components/progress-components", 13 | "---Hooks---", 14 | "../react/hooks/use-progress", 15 | "hooks/use-router", 16 | "---Advanced---", 17 | "data-attributes" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /apps/docs/content/docs/other-projects.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Other Projects 3 | description: Explore other open-source tools and developer utilities created by the author of BProgress. 4 | --- 5 | 6 | ### Animate UI 7 | 8 | **Animate UI** is a **fully animated, open-source component distribution** built with React, TypeScript, Tailwind CSS, and Motion. Browse a list of components you can install, modify, and use in your projects. 9 | 10 | More information can be found [here](https://animate-ui.com). 11 | 12 | 21 | 22 | ### Next MW 23 | 24 | Create **multiple middlewares** quickly and easily in Next.js. 25 | 26 | More information can be found [here](https://next-mw-docs.vercel.app). 27 | -------------------------------------------------------------------------------- /apps/docs/content/docs/pause.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: pause() 3 | description: BProgress.pause() method 4 | --- 5 | 6 | The `pause()` method is used to pause the progress bar. 7 | 8 | ## Usage 9 | 10 | ```js 11 | BProgress.pause(); 12 | ``` 13 | 14 | ## Typing 15 | 16 | ```ts 17 | BProgress.pause(): BProgress; 18 | ``` 19 | -------------------------------------------------------------------------------- /apps/docs/content/docs/promise.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: promise() 3 | description: BProgress.promise() method 4 | --- 5 | 6 | The `promise()` method integrates BProgress with a "promise-like" object (e.g., jQuery promises), automatically starting the progress bar and completing it when the promise is resolved. 7 | 8 | ## Usage 9 | 10 | ```js 11 | // Assume $promise is a jQuery promise-like 12 | BProgress.promise($promise); 13 | ``` 14 | 15 | ## Typing 16 | 17 | ```ts 18 | BProgress.promise($promise: any): BProgress; 19 | ``` 20 | 21 | ## Parameters 22 | 23 | | Name | Type | Description | 24 | |----------|------|--------------------------------------------------| 25 | | $promise | any | A jQuery-like promise object (with an .always() callback). | 26 | -------------------------------------------------------------------------------- /apps/docs/content/docs/quick-start.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Quick Start 3 | description: Get started with BProgress 4 | --- 5 | 6 | ## Import 7 | 8 | ### CDN 9 | 10 | Import CSS in your `index.html` file. 11 | 12 | ```html 13 | 14 | ``` 15 | 16 | Import JavaScript in your `index.html` file using the modern import syntax: 17 | 18 | ```html 19 | 26 | ``` 27 | 28 | Or you can add `BProgressJS` as a global variable using the legacy include: 29 | 30 | ```html 31 | 32 | 39 | ``` 40 | 41 | ### Node.js 42 | 43 | ```js 44 | import '@bprogress/core/css'; 45 | import { BProgress } from '@bprogress/core'; 46 | ``` 47 | 48 | ## Basic Usage 49 | 50 | Simply call `start()` and `done()` to control the progress bar. 51 | 52 | ```js 53 | BProgress.start(); 54 | BProgress.done(); 55 | ``` 56 | -------------------------------------------------------------------------------- /apps/docs/content/docs/react/components/progress-components/bar.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Bar 3 | description: Use the `Bar` component 4 | --- 5 | 6 | The `Bar` component must be used inside the `Progress` component. 7 | 8 | ## Import 9 | 10 | ```tsx 11 | import { Bar } from '@bprogress/...'; 12 | ``` 13 | 14 | 15 | Replace the `...` in the import with the library you're using. For example, if you use `@bprogress/next`, import by doing `from '@bprogress/next'` 16 | 17 | 18 | ## Usage 19 | 20 | The `Bar` component is used to create the progress bar element. 21 | 22 | ```tsx 23 | 24 | ``` 25 | 26 | It can be used with a children (like `Peg` or your custom component) like this: 27 | 28 | ```tsx 29 | 30 | 31 | 32 | ``` 33 | 34 | ## Props 35 | 36 | | Name | Type | Default | Description | 37 | | --- | --- | --- | --- | 38 | | as | `React.ElementType` | `'div'` | The component to render the progress element | 39 | | children | `React.ReactNode` | `undefinded` | The children of the progress element | 40 | | classSelector | `string` | `'bar'` | The class selector of the progress element (depends on your css) | 41 | | ...rest | `React.ComponentPropsWithoutRef` | - | The rest of the props are passed to the progress element | 42 | -------------------------------------------------------------------------------- /apps/docs/content/docs/react/components/progress-components/indeterminate.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Indeterminate 3 | description: Use the `Indeterminate` component 4 | --- 5 | 6 | The `Indeterminate` component must be used inside the `Progress` component. 7 | 8 | ## Import 9 | 10 | ```tsx 11 | import { Indeterminate } from '@bprogress/...'; 12 | ``` 13 | 14 | 15 | Replace the `...` in the import with the library you're using. For example, if you use `@bprogress/next`, import by doing `from '@bprogress/next'` 16 | 17 | 18 | ## Usage 19 | 20 | The `Indeterminate` component is used to create the indeterminate progress bar element. 21 | 22 | ```tsx 23 | 24 | ``` 25 | 26 | 27 | It's only useful if you use the BProgress `indeterminate` option. 28 | 29 | 30 | ## Props 31 | 32 | | Name | Type | Default | Description | 33 | | --- | --- | --- | --- | 34 | | as | `React.ElementType` | `'div'` | The component to render the progress element | 35 | | classSelector | `string` | `'indeterminate'` | The class selector of the progress element (depends on your css) | 36 | | ...rest | `React.ComponentPropsWithoutRef` | - | The rest of the props are passed to the progress element | 37 | -------------------------------------------------------------------------------- /apps/docs/content/docs/react/components/progress-components/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Progress Components", 3 | "root": false, 4 | "pages": [ 5 | "progress", 6 | "bar", 7 | "peg", 8 | "spinner", 9 | "spinner-icon", 10 | "indeterminate" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /apps/docs/content/docs/react/components/progress-components/peg.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Peg 3 | description: Use the `Peg` component 4 | --- 5 | 6 | The `Peg` component must be used inside the `Bar` component. 7 | 8 | ## Import 9 | 10 | ```tsx 11 | import { Peg } from '@bprogress/...'; 12 | ``` 13 | 14 | 15 | Replace the `...` in the import with the library you're using. For example, if you use `@bprogress/next`, import by doing `from '@bprogress/next'` 16 | 17 | 18 | ## Usage 19 | 20 | The `Peg` component is used to create a shadow that acts like a luminous halo. 21 | 22 | ```tsx 23 | 24 | ``` 25 | 26 | The `Peg` component can be used with children. 27 | 28 | ## Props 29 | 30 | | Name | Type | Default | Description | 31 | | --- | --- | --- | --- | 32 | | as | `React.ElementType` | `'div'` | The component to render the progress element | 33 | | children | `React.ReactNode` | `undefinded` | The children of the progress element | 34 | | classSelector | `string` | `'peg'` | The class selector of the progress element (depends on your css) | 35 | | ...rest | `React.ComponentPropsWithoutRef` | - | The rest of the props are passed to the progress element | 36 | -------------------------------------------------------------------------------- /apps/docs/content/docs/react/components/progress-components/spinner-icon.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: SpinnerIcon 3 | description: Use the `SpinnerIcon` component 4 | --- 5 | 6 | The `SpinnerIcon` component must be used inside the `Spinner` component. 7 | 8 | ## Import 9 | 10 | ```tsx 11 | import { SpinnerIcon } from '@bprogress/...'; 12 | ``` 13 | 14 | 15 | Replace the `...` in the import with the library you're using. For example, if you use `@bprogress/next`, import by doing `from '@bprogress/next'` 16 | 17 | 18 | ## Usage 19 | 20 | This component is used to display the spinner icon. 21 | 22 | ```tsx 23 | 24 | ``` 25 | 26 | ## Props 27 | 28 | | Name | Type | Default | Description | 29 | | --- | --- | --- | --- | 30 | | as | `React.ElementType` | `'div'` | The component to render the progress element | 31 | | children | `React.ReactNode` | `undefinded` | The children of the progress element | 32 | | classSelector | `string` | `'peg'` | The class selector of the progress element (depends on your css) | 33 | | ...rest | `React.ComponentPropsWithoutRef` | - | The rest of the props are passed to the progress element | 34 | -------------------------------------------------------------------------------- /apps/docs/content/docs/react/components/progress-components/spinner.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Spinner 3 | description: Use the `Spinner` component 4 | --- 5 | 6 | The `Spinner` component must be used inside the `Progress` component. 7 | 8 | ## Import 9 | 10 | ```tsx 11 | import { Spinner } from '@bprogress/...'; 12 | ``` 13 | 14 | 15 | Replace the `...` in the import with the library you're using. For example, if you use `@bprogress/next`, import by doing `from '@bprogress/next'` 16 | 17 | 18 | ## Usage 19 | 20 | This component is used to display the spinner. 21 | 22 | ```tsx 23 | 24 | ``` 25 | 26 | It can be used with a children like `SpinnerIcon`: 27 | 28 | ```tsx 29 | 30 | 31 | 32 | ``` 33 | 34 | Or with a custom spinner component like this: 35 | 36 | ```tsx 37 | 38 | 39 | 40 | ``` 41 | 42 | ## Props 43 | 44 | | Name | Type | Default | Description | 45 | | --- | --- | --- | --- | 46 | | as | `React.ElementType` | `'div'` | The component to render the progress element | 47 | | children | `React.ReactNode` | `undefinded` | The children of the progress element | 48 | | classSelector | `string` | `'spinner'` | The class selector of the progress element (depends on your css) | 49 | | ...rest | `React.ComponentPropsWithoutRef` | - | The rest of the props are passed to the progress element | 50 | -------------------------------------------------------------------------------- /apps/docs/content/docs/react/components/progress-provider.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: ProgressProvider 3 | description: How to use ProgressProvider 4 | --- 5 | 6 | import { ProgressTypeTable } from '../../../../components/progress-type-table'; 7 | import { SiCsswizardry } from 'react-icons/si'; 8 | 9 | ## Import 10 | 11 | ```tsx 12 | import { ProgressProvider } from '@bprogress/react'; 13 | ``` 14 | 15 | ## Usage 16 | 17 | ```tsx 18 | ... 19 | ``` 20 | 21 | ## Props 22 | 23 | 40 | 41 | ## Links 42 | 43 | 44 | } 47 | title="BProgress CSS" 48 | href="https://github.com/imskyleen/bprogress/blob/main/packages/core/index.css" 49 | description="Default BProgress CSS" 50 | /> 51 | 52 | -------------------------------------------------------------------------------- /apps/docs/content/docs/react/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "React", 3 | "root": false, 4 | "pages": [ 5 | "---Guide---", 6 | "installation", 7 | "quick-start", 8 | "---Components---", 9 | "components/progress-provider", 10 | "components/progress-components", 11 | "---Hooks---", 12 | "hooks/use-progress", 13 | "hooks/use-anchor-progress", 14 | "---Utils---", 15 | "utils/with-memo", 16 | "utils/with-suspense" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /apps/docs/content/docs/react/quick-start.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Quick Start 3 | description: Get started with BProgress in your React application 4 | --- 5 | 6 | import { SiNextdotjs } from "react-icons/si"; 7 | import { HiDotsHorizontal } from "react-icons/hi"; 8 | 9 | ## Import 10 | 11 | ```tsx 12 | import { ProgressProvider } from '@bprogress/react'; 13 | ``` 14 | 15 | ## Usage 16 | 17 | ```tsx 18 | 19 | ... 20 | 21 | ``` 22 | 23 | ## Example 24 | 25 | ```tsx title="src/index.tsx" 26 | import React from 'react'; 27 | import ReactDOM from 'react-dom/client'; 28 | import './index.css'; 29 | import App from './App'; 30 | import { ProgressProvider } from '@bprogress/react'; 31 | 32 | const root = ReactDOM.createRoot( 33 | document.getElementById('root') as HTMLElement, 34 | ); 35 | root.render( 36 | 37 | 38 | 39 | 40 | , 41 | ); 42 | ``` 43 | 44 | ```tsx title="src/App.tsx" 45 | import { useProgress } from '@bprogress/react'; 46 | 47 | function App() { 48 | const { start, stop, pause, resume } = useProgress(); 49 | 50 | return ( 51 |
52 | 53 | 54 | 55 | 56 |
57 | ); 58 | } 59 | 60 | export default App; 61 | ``` 62 | -------------------------------------------------------------------------------- /apps/docs/content/docs/react/utils/with-memo.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: With Memo 3 | description: Used to wrap your Progress component with a memo to optimize performance 4 | --- 5 | 6 | ## `withMemo()` 7 | 8 | ### Import 9 | 10 | ```ts 11 | import { withMemo } from '@bprogress/react'; 12 | ``` 13 | 14 | ### Type 15 | 16 | ```ts 17 | function withMemo

(Component: React.ComponentType

, ignoreKeys?: string[]): React.MemoExoticComponent>; 21 | ``` -------------------------------------------------------------------------------- /apps/docs/content/docs/react/utils/with-suspense.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: With Suspense 3 | description: Used to surround your component with Suspense 4 | --- 5 | 6 | ## `withSuspense()` 7 | 8 | ### Import 9 | 10 | ```ts 11 | import { withSuspense } from '@bprogress/react'; 12 | ``` 13 | 14 | ### Type 15 | 16 | ```ts 17 | function withSuspense

(Component: ComponentType

): (props: P) => React.JSX.Element; 18 | ``` 19 | -------------------------------------------------------------------------------- /apps/docs/content/docs/remix/data-attributes/disable-progress.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Disable progress 3 | description: Disable the progress bar on specific links 4 | --- 5 | 6 | import { Callout } from 'fumadocs-ui/components/callout'; 7 | 8 | You can disable the progress bar on specific links by adding the `data-disable-progress={true}` attribute. 9 | 10 | 11 | This will not work for Link in svg elements. 12 | 13 | 14 | ## Usage 15 | 16 | ```tsx 17 | 18 | Features 19 | 20 | ``` 21 | -------------------------------------------------------------------------------- /apps/docs/content/docs/remix/data-attributes/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Data Attributes", 3 | "root": false, 4 | "pages": ["disable-progress", "prevent-progress"] 5 | } 6 | -------------------------------------------------------------------------------- /apps/docs/content/docs/remix/data-attributes/prevent-progress.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Prevent progress 3 | description: Prevent the progress bar from starting 4 | --- 5 | 6 | import { Callout } from 'fumadocs-ui/components/callout'; 7 | 8 | You can prevent the progress bar from starting by adding the `data-prevent-progress={true}` attribute. 9 | 10 | ## Usage 11 | 12 | ```tsx 13 | 14 | Dashboard 15 | e.preventDefault()} data-prevent-progress={true}> 16 | preventDefault 17 | 18 | 19 | ``` 20 | -------------------------------------------------------------------------------- /apps/docs/content/docs/remix/installation.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation 3 | description: Install BProgress in your Remix application 4 | --- 5 | 6 | import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; 7 | import { SiNpm } from 'react-icons/si'; 8 | import { FaGithub } from 'react-icons/fa6'; 9 | 10 | ## Installation 11 | 12 | To install BProgress, run the following command: 13 | 14 | 15 | ```bash npm install @bprogress/remix ``` 16 | ```bash pnpm add @bprogress/remix ``` 17 | ```bash yarn add @bprogress/remix ``` 18 | ```bash bun add @bprogress/remix ``` 19 | 20 | 21 | Now you are ready to use BProgress in your Remix application! 22 | 23 | 24 | This package requires Remix version 2. 25 | 26 | 27 | ## Links 28 | 29 | 30 | } 35 | > 36 | Check the package on NPM 37 | 38 | } 43 | > 44 | Check the repository on GitHub 45 | 46 | 47 | -------------------------------------------------------------------------------- /apps/docs/content/docs/remix/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Remix", 3 | "root": false, 4 | "pages": [ 5 | "---Guide---", 6 | "installation", 7 | "quick-start", 8 | "---Components---", 9 | "components/progress-provider", 10 | "../react/components/progress-components", 11 | "---Hooks---", 12 | "../react/hooks/use-progress", 13 | "hooks/use-navigate", 14 | "---Advanced---", 15 | "data-attributes" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /apps/docs/content/docs/remix/quick-start.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Quick Start 3 | description: Get started with BProgress for Remix 4 | --- 5 | 6 | ## Import 7 | 8 | Import into your `/app/root(.jsx/.tsx)` folder. 9 | 10 | ```tsx 11 | import { ProgressProvider } from '@bprogress/remix'; 12 | ``` 13 | 14 | ## Usage 15 | 16 | ```tsx 17 | 18 | ... 19 | 20 | ``` 21 | 22 | ## Example 23 | 24 | ```tsx title="app/root.tsx" 25 | import { 26 | Links, 27 | Meta, 28 | Outlet, 29 | Scripts, 30 | ScrollRestoration, 31 | } from '@remix-run/react'; 32 | import type { LinksFunction } from '@remix-run/node'; 33 | import { ProgressProvider } from '@bprogress/remix'; 34 | 35 | import './tailwind.css'; 36 | 37 | export const links: LinksFunction = () => [ 38 | { rel: 'preconnect', href: 'https://fonts.googleapis.com' }, 39 | { 40 | rel: 'preconnect', 41 | href: 'https://fonts.gstatic.com', 42 | crossOrigin: 'anonymous', 43 | }, 44 | { 45 | rel: 'stylesheet', 46 | href: 'https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap', 47 | }, 48 | ]; 49 | 50 | export function Layout({ children }: { children: React.ReactNode }) { 51 | return ( 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | {children} 61 | 62 | 63 | 64 | 65 | ); 66 | } 67 | 68 | export default function App() { 69 | return ; 70 | } 71 | ``` -------------------------------------------------------------------------------- /apps/docs/content/docs/remove.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: remove() 3 | description: BProgress.remove() method 4 | --- 5 | 6 | The `remove()` method removes one or all `.bprogress` elements from the DOM. 7 | 8 | ## Usage 9 | 10 | ```js 11 | // Remove a specific element 12 | const element = document.querySelector('#my-progress'); 13 | BProgress.remove(element); 14 | 15 | // Remove all 16 | BProgress.remove(); 17 | ``` 18 | 19 | ## Typing 20 | 21 | ```ts 22 | BProgress.remove(progressElement?: HTMLElement): void; 23 | ``` 24 | 25 | ## Parameters 26 | 27 | | Name | Type | Description | 28 | |-------|---------|--------------------------------------------------------------------| 29 | | progressElement | HTMLElement | If provided, removes or hides only that element. Otherwise removes all. | 30 | 31 | _If `template === null`, the element(s) are hidden (via `display: none`) instead of being fully removed._ 32 | -------------------------------------------------------------------------------- /apps/docs/content/docs/render.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: render() 3 | description: BProgress.render() method 4 | --- 5 | 6 | The `render()` method ensures a `.bprogress` element is present in the DOM. If `template` is not `null`, it creates it if missing. Otherwise, it relies on a user-provided element. 7 | 8 | ## Usage 9 | 10 | ```js 11 | BProgress.render(true); 12 | ``` 13 | 14 | ## Typing 15 | 16 | ```ts 17 | BProgress.render(fromStart: boolean = false): HTMLElement[]; 18 | ``` 19 | 20 | ## Parameters 21 | 22 | | Name | Type | Description | 23 | |-----------|---------|-----------------------------------------------------------------------------| 24 | | fromStart | boolean | If `true`, the bar is rendered at 0% (used internally when starting for the first time) | -------------------------------------------------------------------------------- /apps/docs/content/docs/reset.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: reset() 3 | description: BProgress.reset() method 4 | --- 5 | 6 | The `reset()` method is used to reset the progress bar to the default state. 7 | 8 | ## Usage 9 | 10 | ```js 11 | BProgress.reset(); 12 | ``` 13 | 14 | ## Typing 15 | 16 | ```ts 17 | BProgress.reset(): BProgress; 18 | ``` 19 | -------------------------------------------------------------------------------- /apps/docs/content/docs/resume.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: resume() 3 | description: BProgress.resume() method 4 | --- 5 | 6 | The `resume()` method is used to resume the progress bar after it has been paused. 7 | 8 | ## Usage 9 | 10 | ```js 11 | BProgress.resume(); 12 | ``` 13 | 14 | ## Typing 15 | 16 | ```ts 17 | BProgress.resume(): BProgress; 18 | ``` 19 | -------------------------------------------------------------------------------- /apps/docs/content/docs/roadmap.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Roadmap 3 | description: The roadmap for the BProgress project. 4 | --- 5 | 6 | The following roadmap outlines the planned development stages for **BProgress**. These steps are subject to change based on community feedback and technological advancements. 7 | 8 | ## Short Term 9 | 10 | * **Add CSS Variables for `@bprogress/core`** 11 | * [x] Enable easy customization of the progress bar using CSS variables. 12 | 13 | * **Improve Accessibility Practices** 14 | * [x] Replace ARIA roles with CSS class selectors for better flexibility and compatibility. 15 | *(See: [ARIA Techniques](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques))* 16 | 17 | ## Medium Term 18 | 19 | * **Develop Framework Integration Packages** 20 | * [x] Create React package 21 | * [x] Create Next.js package 22 | * [x] Create Remix package 23 | * [x] Create Vue package 24 | * [ ] Create Nuxt.js package 25 | * [ ] Create Svelte package 26 | 27 | - **Enhance Documentation and Provide Examples** 28 | * [x] Add detailed documentation for each package. 29 | 30 | - **Implement a Comprehensive Testing Suite** 31 | * [x] core 32 | * [x] react 33 | * [x] vue 34 | * [ ] next 35 | * [ ] remix 36 | * [ ] nuxt 37 | * [ ] svelte 38 | 39 | ## Long Term 40 | 41 | - **Continuous Improvement Based on User Feedback** 42 | Refine packages and features according to community needs and feedback. 43 | 44 | - **Explore New Features** 45 | Identify and implement advanced features to further enhance the user experience (additional animations, advanced configurations, etc.). 46 | -------------------------------------------------------------------------------- /apps/docs/content/docs/same-url.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Same URL 3 | description: Used to detect whether the starting URL is the same as the target URL 4 | --- 5 | 6 | ## `isSameURL()` 7 | 8 | ### Import 9 | 10 | ```ts 11 | import { isSameURL } from '@bprogress/react'; 12 | ``` 13 | 14 | ### Type 15 | 16 | ```ts 17 | function isSameURL(target: URL, current: URL): boolean; 18 | ``` 19 | 20 | ## `isSameURLWithoutSearch()` 21 | 22 | ### Import 23 | 24 | ```ts 25 | import { isSameURLWithoutSearch } from '@bprogress/react'; 26 | ``` 27 | 28 | ### Type 29 | 30 | ```ts 31 | function isSameURLWithoutSearch(target: URL, current: URL): boolean; 32 | ``` 33 | -------------------------------------------------------------------------------- /apps/docs/content/docs/set.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: set() 3 | description: BProgress.set() method 4 | --- 5 | 6 | The `set()` method is used to set the progress bar to a specific percentage. 7 | 8 | ## Usage 9 | 10 | ```js 11 | BProgress.set(0.5); 12 | ``` 13 | 14 | ## Typing 15 | 16 | ```ts 17 | BProgress.set(n: number): BProgress; 18 | ``` 19 | 20 | ## Parameters 21 | 22 | | Name | Type | Description | 23 | |------|--------|----------------------| 24 | | n | number | The percentage value between 0 and 1 | 25 | 26 | -------------------------------------------------------------------------------- /apps/docs/content/docs/start.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: start() 3 | description: BProgress.start() method 4 | --- 5 | 6 | The `start()` method is used to start the progress bar. 7 | 8 | ## Usage 9 | 10 | ```js 11 | BProgress.start(); 12 | ``` 13 | 14 | ## Typing 15 | 16 | ```ts 17 | BProgress.start(): BProgress; 18 | ``` 19 | -------------------------------------------------------------------------------- /apps/docs/content/docs/trickle.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: trickle() 3 | description: BProgress.trickle() method 4 | --- 5 | 6 | The `trickle()` method increments the progress bar by a small amount, giving the impression of gradual progress. 7 | 8 | ## Usage 9 | 10 | ```js 11 | BProgress.trickle(); 12 | ``` 13 | 14 | ## Typing 15 | 16 | ```ts 17 | BProgress.trickle(): BProgress; 18 | ``` 19 | -------------------------------------------------------------------------------- /apps/docs/content/docs/vue/components/progress-components/bar.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Bar 3 | description: Use the `Bar` component 4 | --- 5 | 6 | The `Bar` component must be used inside the `Progress` component. 7 | 8 | ## Import 9 | 10 | ```vue 11 | 14 | ``` 15 | 16 | 17 | Replace the `...` in the import with the library you're using. For example, if you use `@bprogress/nuxt`, import by doing `from '@bprogress/nuxt'` 18 | 19 | 20 | ## Usage 21 | 22 | The `Bar` component is used to create the progress bar element. 23 | 24 | ```vue 25 | 28 | ``` 29 | 30 | It can also be used with a slot to insert a child component (like a custom component) as follows: 31 | 32 | ```vue 33 | 38 | ``` 39 | 40 | ## Props 41 | 42 | | Name | Type | Default | Description | 43 | | --- | --- | --- | --- | 44 | | is | `string \| Component` | `'div'` | The component or HTML element to render. This prop uses Vue's is attribute for dynamic rendering. | 45 | | class | `ClassValue` | `undefinded` | The class of the progress element | 46 | | classSelector | `string` | `'bar'` | The class selector of the progress element (depends on your css) | 47 | | ...rest | `HTMLAttributes` | - | Other attributes passed down to the rendered element | 48 | -------------------------------------------------------------------------------- /apps/docs/content/docs/vue/components/progress-components/indeterminate.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Indeterminate 3 | description: Use the `Indeterminate` component 4 | --- 5 | 6 | The `Indeterminate` component must be used inside the `Progress` component. 7 | 8 | ## Import 9 | 10 | ```vue 11 | 14 | ``` 15 | 16 | 17 | Replace the `...` in the import with the library you're using. For example, if you use `@bprogress/nuxt`, import by doing `from '@bprogress/nuxt'` 18 | 19 | 20 | ## Usage 21 | 22 | The `Indeterminate` component is used to create the indeterminate progress bar element. 23 | 24 | ```vue 25 | 28 | ``` 29 | 30 | 31 | It's only useful if you use the BProgress `indeterminate` option. 32 | 33 | 34 | ## Props 35 | 36 | | Name | Type | Default | Description | 37 | | --- | --- | --- | --- | 38 | | is | `string \| Component` | `'div'` | The component or HTML element to render. This prop uses Vue's is attribute for dynamic rendering. | 39 | | class | `ClassValue` | `undefinded` | The class of the progress element | 40 | | classSelector | `string` | `'indeterminate'` | The class selector of the progress element (depends on your css) | 41 | | ...rest | `HTMLAttributes` | - | Other attributes passed down to the rendered element | 42 | -------------------------------------------------------------------------------- /apps/docs/content/docs/vue/components/progress-components/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Progress Components", 3 | "root": false, 4 | "pages": [ 5 | "progress", 6 | "bar", 7 | "peg", 8 | "spinner", 9 | "spinner-icon", 10 | "indeterminate" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /apps/docs/content/docs/vue/components/progress-components/peg.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Peg 3 | description: Use the `Peg` component 4 | --- 5 | 6 | The `Peg` component must be used inside the `Bar` component. 7 | 8 | ## Import 9 | 10 | ```vue 11 | 14 | ``` 15 | 16 | 17 | Replace the `...` in the import with the library you're using. For example, if you use `@bprogress/nuxt`, import by doing `from '@bprogress/nuxt'` 18 | 19 | 20 | ## Usage 21 | 22 | The `Peg` component is used to create a shadow that acts like a luminous halo. 23 | 24 | ```vue 25 | 28 | ``` 29 | 30 | It can also be used with a slot to insert a child component. 31 | 32 | ## Props 33 | 34 | | Name | Type | Default | Description | 35 | | --- | --- | --- | --- | 36 | | is | `string \| Component` | `'div'` | The component or HTML element to render. This prop uses Vue's is attribute for dynamic rendering. | 37 | | class | `ClassValue` | `undefinded` | The class of the progress element | 38 | | classSelector | `string` | `'peg'` | The class selector of the progress element (depends on your css) | 39 | | ...rest | `HTMLAttributes` | - | Other attributes passed down to the rendered element | 40 | -------------------------------------------------------------------------------- /apps/docs/content/docs/vue/components/progress-components/spinner-icon.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: SpinnerIcon 3 | description: Use the `SpinnerIcon` component 4 | --- 5 | 6 | The `SpinnerIcon` component must be used inside the `Spinner` component. 7 | 8 | ## Import 9 | 10 | ```vue 11 | 14 | ``` 15 | 16 | 17 | Replace the `...` in the import with the library you're using. For example, if you use `@bprogress/nuxt`, import by doing `from '@bprogress/nuxt'` 18 | 19 | 20 | ## Usage 21 | 22 | This component is used to display the spinner icon. 23 | 24 | ```vue 25 | 28 | ``` 29 | 30 | ## Props 31 | 32 | | Name | Type | Default | Description | 33 | | --- | --- | --- | --- | 34 | | is | `string \| Component` | `'div'` | The component or HTML element to render. This prop uses Vue's is attribute for dynamic rendering. | 35 | | class | `ClassValue` | `undefinded` | The class of the progress element | 36 | | classSelector | `string` | `'peg'` | The class selector of the progress element (depends on your css) | 37 | | ...rest | `HTMLAttributes` | - | Other attributes passed down to the rendered element | 38 | -------------------------------------------------------------------------------- /apps/docs/content/docs/vue/components/progress-components/spinner.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Spinner 3 | description: Use the `Spinner` component 4 | --- 5 | 6 | The `Spinner` component must be used inside the `Progress` component. 7 | 8 | ## Import 9 | 10 | ```vue 11 | 14 | ``` 15 | 16 | 17 | Replace the `...` in the import with the library you're using. For example, if you use `@bprogress/nuxt`, import by doing `from '@bprogress/nuxt'` 18 | 19 | 20 | ## Usage 21 | 22 | This component is used to display the spinner. 23 | 24 | ```vue 25 | 28 | ``` 29 | 30 | It can also be used with a slot to insert a child component (like a custom component) as follows: 31 | 32 | ```vue 33 | 38 | ``` 39 | 40 | Or with a custom spinner component like this: 41 | 42 | ```tsx 43 | 48 | ``` 49 | 50 | ## Props 51 | 52 | | Name | Type | Default | Description | 53 | | --- | --- | --- | --- | 54 | | is | `string \| Component` | `'div'` | The component or HTML element to render. This prop uses Vue's is attribute for dynamic rendering. | 55 | | class | `ClassValue` | `undefinded` | The class of the progress element | 56 | | classSelector | `string` | `'spinner'` | The class selector of the progress element (depends on your css) | 57 | | ...rest | `HTMLAttributes` | - | Other attributes passed down to the rendered element | 58 | -------------------------------------------------------------------------------- /apps/docs/content/docs/vue/components/progress-provider.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: ProgressProvider 3 | description: How to use ProgressProvider 4 | --- 5 | 6 | import { ProgressTypeTable } from '../../../../components/progress-type-table'; 7 | import { SiCsswizardry } from 'react-icons/si'; 8 | 9 | ## Import 10 | 11 | ```tsx 12 | import { ProgressProvider } from '@bprogress/vue'; 13 | ``` 14 | 15 | ## Usage 16 | 17 | ```vue 18 | 19 | ... 20 | 21 | ``` 22 | 23 | ## Props 24 | 25 | 36 | 37 | ## Links 38 | 39 | 40 | } 43 | title="BProgress CSS" 44 | href="https://github.com/imskyleen/bprogress/blob/main/packages/core/index.css" 45 | description="Default BProgress CSS" 46 | /> 47 | 48 | -------------------------------------------------------------------------------- /apps/docs/content/docs/vue/composables/use-anchor-progress.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: useAnchorProgress 3 | description: Use `useAnchorProgress` composable 4 | --- 5 | 6 | import { ProgressTypeTable } from '../../../../components/progress-type-table'; 7 | 8 | There are two ways to set up a progress bar that is triggered during navigation: 9 | 1. **If the framework has a router that detects the start and end of navigation**, you can use the `useProgress` composable to trigger the progress bar at the start of navigation and stop it when you reach the target page. 10 | 2. **If the framework has a router that doesn't provide built-in navigation detection**, you can use this `useAnchorProgress` composable to activate navigation detection based on `` elements in the DOM and `window.history`. 11 | 12 | ## Import 13 | 14 | ```tsx 15 | import { useAnchorProgress } from '@bprogress/vue'; 16 | ``` 17 | 18 | ## Usage 19 | 20 | ```tsx 21 | useAnchorProgress( 22 | { 23 | shallowRouting, 24 | disableSameURL, 25 | startPosition, 26 | delay, 27 | stopDelay, 28 | targetPreprocessor, 29 | disableAnchorClick, 30 | startOnLoad, 31 | }, 32 | [navigation], 33 | ) 34 | ``` 35 | 36 | ## Parameters 37 | 38 | ```ts 39 | function useAnchorProgress(options: UseAnchorProgressOptions, deps: any[]): void; 40 | ``` 41 | 42 | ### Options 43 | 44 | 47 | 48 | ## Example 49 | 50 | ```vue title="Progress.vue" 51 | 67 | ``` 68 | -------------------------------------------------------------------------------- /apps/docs/content/docs/vue/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Vue", 3 | "root": false, 4 | "pages": [ 5 | "---Guide---", 6 | "installation", 7 | "quick-start", 8 | "---Components---", 9 | "components/progress-provider", 10 | "components/progress-components", 11 | "---Composables---", 12 | "composables/use-progress", 13 | "composables/use-anchor-progress" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /apps/docs/content/docs/vue/quick-start.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Quick Start 3 | description: Get started with BProgress in your Vue application 4 | --- 5 | 6 | import { SiNextdotjs } from "react-icons/si"; 7 | import { HiDotsHorizontal } from "react-icons/hi"; 8 | 9 | ## Import 10 | 11 | ```tsx 12 | import { ProgressProvider } from '@bprogress/vue'; 13 | ``` 14 | 15 | ## Usage 16 | 17 | ```vue 18 | 19 | ... 20 | 21 | ``` 22 | 23 | ## Example 24 | 25 | ```vue title="src/Root.vue" 26 | 30 | 31 | 36 | ``` 37 | 38 | ```ts title="src/main.ts" 39 | import { createApp } from 'vue'; 40 | import Root from './Root.vue'; 41 | 42 | createApp(Root).mount('#app'); 43 | ``` 44 | 45 | ```vue title="src/App.vue" 46 | 51 | 52 | 58 | ``` 59 | -------------------------------------------------------------------------------- /apps/docs/lib/source.ts: -------------------------------------------------------------------------------- 1 | import { docs, meta } from '@/.source'; 2 | import { createMDXSource } from 'fumadocs-mdx'; 3 | import { loader } from 'fumadocs-core/source'; 4 | 5 | export const source = loader({ 6 | baseUrl: '/docs', 7 | source: createMDXSource(docs, meta), 8 | }); 9 | -------------------------------------------------------------------------------- /apps/docs/next.config.mjs: -------------------------------------------------------------------------------- 1 | import { createMDX } from 'fumadocs-mdx/next'; 2 | 3 | const withMDX = createMDX(); 4 | 5 | /** @type {import('next').NextConfig} */ 6 | const config = { 7 | reactStrictMode: true, 8 | transpilePackages: ['@workspace/ui'], 9 | }; 10 | 11 | export default withMDX(config); 12 | -------------------------------------------------------------------------------- /apps/docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "next build", 7 | "dev": "next dev -p 3001", 8 | "start": "next start", 9 | "postinstall": "fumadocs-mdx" 10 | }, 11 | "dependencies": { 12 | "@bprogress/next": "workspace:*", 13 | "@radix-ui/react-slot": "^1.1.2", 14 | "@radix-ui/react-switch": "^1.1.3", 15 | "@workspace/ui": "workspace:*", 16 | "class-variance-authority": "^0.7.1", 17 | "clsx": "^2.1.1", 18 | "framer-motion": "^12.4.3", 19 | "fumadocs-core": "14.6.0", 20 | "fumadocs-mdx": "11.1.2", 21 | "fumadocs-ui": "14.6.0", 22 | "lucide-react": "^0.468.0", 23 | "mini-svg-data-uri": "^1.4.4", 24 | "next": "15.0.4", 25 | "next-themes": "^0.4.4", 26 | "prettier": "^3.2.5", 27 | "react": "^19.0.0", 28 | "react-dom": "^19.0.0", 29 | "react-icons": "^5.4.0", 30 | "react-syntax-highlighter": "^15.6.1", 31 | "tailwind-merge": "^2.6.0", 32 | "tailwindcss-animate": "^1.0.7", 33 | "typescript": "^5.7.2" 34 | }, 35 | "devDependencies": { 36 | "@types/mdx": "^2.0.13", 37 | "@types/node": "22.10.1", 38 | "@types/react": "^19.0.1", 39 | "@types/react-dom": "^19.0.2", 40 | "@types/react-syntax-highlighter": "^15.5.13", 41 | "autoprefixer": "^10.4.20", 42 | "eslint": "^8", 43 | "eslint-config-next": "15.0.4", 44 | "postcss": "^8.4.49", 45 | "tailwindcss": "^3.4.16" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /apps/docs/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from '@workspace/ui/postcss.config'; 2 | -------------------------------------------------------------------------------- /apps/docs/public/animate-ui.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imskyleen/bprogress/f3c776a8d00cbcd55017439bf8a5053f9dbc0976/apps/docs/public/animate-ui.mp4 -------------------------------------------------------------------------------- /apps/docs/site.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | title: 'BProgress', 3 | packages: { 4 | main: '@bprogress/core', 5 | frameworks: { 6 | 'Next.js': '@bprogress/next', 7 | }, 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /apps/docs/source.config.ts: -------------------------------------------------------------------------------- 1 | import { defineDocs, defineConfig } from 'fumadocs-mdx/config'; 2 | 3 | export const { docs, meta } = defineDocs({ 4 | dir: 'content/docs', 5 | }); 6 | 7 | export default defineConfig(); 8 | -------------------------------------------------------------------------------- /apps/docs/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | export * from '@workspace/ui/tailwind.config'; 2 | -------------------------------------------------------------------------------- /apps/docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "target": "ESNext", 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "allowJs": true, 7 | "skipLibCheck": true, 8 | "strict": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "noEmit": true, 11 | "esModuleInterop": true, 12 | "module": "esnext", 13 | "moduleResolution": "bundler", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "jsx": "preserve", 17 | "incremental": true, 18 | "paths": { 19 | "@/*": ["./*"] 20 | }, 21 | "plugins": [ 22 | { 23 | "name": "next" 24 | } 25 | ] 26 | }, 27 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 28 | "exclude": ["node_modules"] 29 | } 30 | -------------------------------------------------------------------------------- /apps/html/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --bprogress-color: red; 3 | --bprogress-height: 4px; 4 | } -------------------------------------------------------------------------------- /apps/next-app-dir/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Playwright 3 | node_modules/ 4 | /test-results/ 5 | /playwright-report/ 6 | /blob-report/ 7 | /playwright/.cache/ 8 | -------------------------------------------------------------------------------- /apps/next-app-dir/__tests__/e2e/example.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "@playwright/test"; 2 | 3 | test("has title", async ({ page }) => { 4 | await page.goto("/"); 5 | 6 | await expect(page).toHaveTitle(/Create Next App/); 7 | }); 8 | -------------------------------------------------------------------------------- /apps/next-app-dir/__tests__/unit/home.test.tsx: -------------------------------------------------------------------------------- 1 | import "@testing-library/jest-dom"; 2 | import { render, screen } from "@testing-library/react"; 3 | import Home from "@/app/[locale]/page"; 4 | 5 | describe("Home", () => { 6 | it("renders a heading", () => { 7 | render(); 8 | 9 | const heading = screen.getByRole("heading", { level: 1 }); 10 | 11 | expect(heading).toBeInTheDocument(); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /apps/next-app-dir/app/[locale]/dashboard/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import Link from 'next/link'; 4 | import { useRouter } from '@bprogress/next/app'; 5 | 6 | const Dashboard = () => { 7 | const router = useRouter(); 8 | 9 | // useEffect(() => { 10 | // setTimeout(() => { 11 | // router.push('/'); 12 | // }, 3000); 13 | // }, [router]); 14 | 15 | return ( 16 | <> 17 | Home 18 | 19 | 22 | 23 | 24 | 25 | 28 | 29 | 35 | 36 | 46 | 47 | ); 48 | }; 49 | 50 | export default Dashboard; 51 | -------------------------------------------------------------------------------- /apps/next-app-dir/app/[locale]/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imskyleen/bprogress/f3c776a8d00cbcd55017439bf8a5053f9dbc0976/apps/next-app-dir/app/[locale]/favicon.ico -------------------------------------------------------------------------------- /apps/next-app-dir/app/[locale]/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | main { 6 | display: flex; 7 | flex-direction: column; 8 | } 9 | 10 | button, a { 11 | all: unset; 12 | color: white; 13 | padding: 7px 15px; 14 | cursor: pointer; 15 | border-radius: 5px; 16 | width: fit-content; 17 | margin-top: 5px; 18 | position: relative; 19 | } 20 | 21 | button:not(.default) { 22 | background-color: red; 23 | } 24 | 25 | button.default { 26 | background-color: green; 27 | } 28 | 29 | button:not(.default)::after { 30 | content: "router.push()"; 31 | } 32 | 33 | button.replace::after { 34 | content: "router.replace()" !important; 35 | } 36 | 37 | button.back::after { 38 | content: "router.back()" !important; 39 | } 40 | 41 | a::after { 42 | content: ""; 43 | } 44 | 45 | a.a::after { 46 | content: ""; 47 | } 48 | 49 | a::after, button::after { 50 | position: absolute; 51 | color: black; 52 | margin-left: 20px; 53 | font-size: 12px; 54 | bottom: 0; 55 | } 56 | 57 | a { 58 | background-color: blue; 59 | } 60 | 61 | :root { 62 | --primary: 220 70% 50%; 63 | } 64 | -------------------------------------------------------------------------------- /apps/next-app-dir/app/[locale]/layout.tsx: -------------------------------------------------------------------------------- 1 | import Providers from './providers'; 2 | import './globals.css'; 3 | import { notFound } from 'next/navigation'; 4 | import { getMessages } from 'next-intl/server'; 5 | import { routing } from '@/i18n/routing'; 6 | import { NextIntlClientProvider } from 'next-intl'; 7 | 8 | export const metadata = { 9 | title: 'Create Next App', 10 | description: 'Generated by create next app', 11 | }; 12 | 13 | export default async function RootLayout({ 14 | children, 15 | params, 16 | }: { 17 | children: React.ReactNode; 18 | params: Promise<{ locale: string }>; 19 | }) { 20 | // Ensure that the incoming `locale` is valid 21 | const { locale } = await params; 22 | if (!routing.locales.includes(locale as any)) { 23 | notFound(); 24 | } 25 | 26 | // Providing all messages to the client 27 | // side is the easiest way to get started 28 | const messages = await getMessages(); 29 | 30 | return ( 31 | 32 | 33 | 34 | {children} 35 | 36 | 37 | 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /apps/next-app-dir/app/[locale]/load/page.tsx: -------------------------------------------------------------------------------- 1 | const LoadPage = async () => { 2 | await new Promise((resolve) => setTimeout(resolve, 5000)); 3 | 4 | return

; 5 | }; 6 | 7 | export default LoadPage; 8 | -------------------------------------------------------------------------------- /apps/next-app-dir/app/[locale]/mounted/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useRouter } from '@bprogress/next/app'; 4 | // import { useRouter } from 'next/navigation'; 5 | import { useEffect, useState } from 'react'; 6 | 7 | const Mounted = () => { 8 | const router = useRouter(); 9 | const [counter, setCounter] = useState(0); 10 | 11 | useEffect(() => { 12 | router.replace('/mounted'); 13 | console.log('Home mounted'); 14 | }, [router, counter]); 15 | 16 | return ( 17 | <> 18 |

BProgress

19 | 20 | 26 | 27 | ); 28 | }; 29 | 30 | export default Mounted; 31 | -------------------------------------------------------------------------------- /apps/next-app-dir/app/[locale]/providers.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { 4 | Bar, 5 | Progress, 6 | AppProgressProvider as ProgressProvider, 7 | Spinner, 8 | SpinnerIcon, 9 | } from '@bprogress/next'; 10 | 11 | const Providers = ({ children }: { children: React.ReactNode }) => { 12 | return ( 13 | 28 |
{children}
29 | 30 |
31 | 32 | 33 | 34 | 35 | 36 | 37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | ); 48 | }; 49 | 50 | export default Providers; 51 | -------------------------------------------------------------------------------- /apps/next-app-dir/eslint.config.js: -------------------------------------------------------------------------------- 1 | import { nextJsConfig } from "@workspace/eslint-config/next-js" 2 | 3 | /** @type {import("eslint").Linter.Config} */ 4 | export default nextJsConfig 5 | -------------------------------------------------------------------------------- /apps/next-app-dir/i18n/navigation.ts: -------------------------------------------------------------------------------- 1 | import { createNavigation } from 'next-intl/navigation'; 2 | import { routing } from './routing'; 3 | 4 | export const { Link, redirect, usePathname, useRouter, getPathname } = 5 | createNavigation(routing); 6 | -------------------------------------------------------------------------------- /apps/next-app-dir/i18n/request.ts: -------------------------------------------------------------------------------- 1 | import { getRequestConfig } from 'next-intl/server'; 2 | import { routing } from './routing'; 3 | 4 | export default getRequestConfig(async ({ requestLocale }) => { 5 | // This typically corresponds to the `[locale]` segment 6 | let locale = await requestLocale; 7 | 8 | // Ensure that a valid locale is used 9 | if (!locale || !routing.locales.includes(locale as any)) { 10 | locale = routing.defaultLocale; 11 | } 12 | 13 | return { 14 | locale, 15 | messages: (await import(`../messages/${locale}.json`)).default, 16 | }; 17 | }); 18 | -------------------------------------------------------------------------------- /apps/next-app-dir/i18n/routing.ts: -------------------------------------------------------------------------------- 1 | import { defineRouting } from 'next-intl/routing'; 2 | 3 | export const routing = defineRouting({ 4 | // A list of all locales that are supported 5 | locales: ['en', 'fr'], 6 | 7 | // Used when no locale matches 8 | defaultLocale: 'en', 9 | }); 10 | -------------------------------------------------------------------------------- /apps/next-app-dir/jest.config.ts: -------------------------------------------------------------------------------- 1 | import nextJest from "next/jest.js"; 2 | 3 | const createJestConfig = nextJest({ 4 | dir: "./", 5 | }); 6 | 7 | const config = { 8 | coverageProvider: "v8", 9 | testEnvironment: "jsdom", 10 | setupFilesAfterEnv: ["/jest.setup.ts"], 11 | testMatch: ["/__tests__/unit/**/*.(spec|test).(js|jsx|ts|tsx)"], 12 | }; 13 | 14 | export default createJestConfig(config) as any; 15 | -------------------------------------------------------------------------------- /apps/next-app-dir/jest.setup.ts: -------------------------------------------------------------------------------- 1 | import "@testing-library/jest-dom"; 2 | -------------------------------------------------------------------------------- /apps/next-app-dir/messages/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "HomePage": { 3 | "title": "Hello world!", 4 | "about": "Go to the about page" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /apps/next-app-dir/messages/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "HomePage": { 3 | "title": "Bonjour le monde!", 4 | "about": "Aller à la page À propos" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /apps/next-app-dir/middleware.ts: -------------------------------------------------------------------------------- 1 | import createMiddleware from 'next-intl/middleware'; 2 | import { routing } from './i18n/routing'; 3 | 4 | export default createMiddleware(routing); 5 | 6 | export const config = { 7 | // Match only internationalized pathnames 8 | matcher: ['/', '/(fr|en)/:path*'], 9 | }; 10 | -------------------------------------------------------------------------------- /apps/next-app-dir/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. 6 | -------------------------------------------------------------------------------- /apps/next-app-dir/next.config.mjs: -------------------------------------------------------------------------------- 1 | import createNextIntlPlugin from "next-intl/plugin"; 2 | 3 | const withNextIntl = createNextIntlPlugin(); 4 | 5 | /** @type {import('next').NextConfig} */ 6 | const nextConfig = { 7 | transpilePackages: ["@workspace/ui", "@bprogress/*"], 8 | }; 9 | 10 | export default withNextIntl(nextConfig); 11 | -------------------------------------------------------------------------------- /apps/next-app-dir/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "next-app-dir", 3 | "version": "0.0.1", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "next dev --turbopack", 8 | "start": "next start", 9 | "test:e2e": "playwright test", 10 | "test:unit": "jest" 11 | }, 12 | "dependencies": { 13 | "@bprogress/next": "workspace:*", 14 | "@workspace/ui": "workspace:*", 15 | "lucide-react": "0.456.0", 16 | "next": "^15.2.0", 17 | "next-intl": "^3.26.5", 18 | "next-themes": "^0.4.3", 19 | "react": "^19.0.0", 20 | "react-dom": "^19.0.0" 21 | }, 22 | "devDependencies": { 23 | "@playwright/test": "^1.51.0", 24 | "@testing-library/dom": "^10.4.0", 25 | "@testing-library/jest-dom": "^6.6.3", 26 | "@testing-library/react": "^16.2.0", 27 | "@types/jest": "^29.5.14", 28 | "@types/node": "^20", 29 | "@types/react": "^19.0.1", 30 | "@types/react-dom": "^19.0.2", 31 | "@workspace/eslint-config": "workspace:^", 32 | "@workspace/typescript-config": "workspace:*", 33 | "jest": "^29.7.0", 34 | "jest-environment-jsdom": "^29.7.0", 35 | "postcss": "^8", 36 | "tailwindcss": "^3.4.1", 37 | "ts-jest": "^29.2.5", 38 | "ts-node": "^10.9.2", 39 | "typescript": "^5" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /apps/next-app-dir/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from "@workspace/ui/postcss.config"; -------------------------------------------------------------------------------- /apps/next-app-dir/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | export * from "@workspace/ui/tailwind.config"; -------------------------------------------------------------------------------- /apps/next-app-dir/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@workspace/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "skipLibCheck": true, 5 | "baseUrl": ".", 6 | "paths": { 7 | "@/*": ["./*"], 8 | "@workspace/ui/*": ["../../packages/ui/src/*"] 9 | }, 10 | "plugins": [ 11 | { 12 | "name": "next" 13 | } 14 | ] 15 | }, 16 | "include": [ 17 | "next-env.d.ts", 18 | "next.config.mjs", 19 | "**/*.ts", 20 | "**/*.tsx", 21 | ".next/types/**/*.ts" 22 | ], 23 | "exclude": ["node_modules"] 24 | } 25 | -------------------------------------------------------------------------------- /apps/pages-app-dir/eslint.config.js: -------------------------------------------------------------------------------- 1 | import { nextJsConfig } from "@workspace/eslint-config/next-js" 2 | 3 | /** @type {import("eslint").Linter.Config} */ 4 | export default nextJsConfig 5 | -------------------------------------------------------------------------------- /apps/pages-app-dir/globals.css: -------------------------------------------------------------------------------- 1 | main { 2 | display: flex; 3 | flex-direction: column; 4 | } 5 | 6 | button, a { 7 | all: unset; 8 | color: white; 9 | padding: 7px 15px; 10 | cursor: pointer; 11 | border-radius: 5px; 12 | width: fit-content; 13 | margin-top: 5px; 14 | position: relative; 15 | } 16 | 17 | button { 18 | background-color: red; 19 | } 20 | 21 | button::after { 22 | content: "router.push()"; 23 | } 24 | 25 | button.back::after { 26 | content: "router.back()" !important; 27 | } 28 | 29 | a::after { 30 | content: ""; 31 | } 32 | 33 | a.a::after { 34 | content: "
"; 35 | } 36 | 37 | a::after, button::after { 38 | position: absolute; 39 | color: black; 40 | margin-left: 20px; 41 | font-size: 10px; 42 | bottom: 0; 43 | } 44 | 45 | a { 46 | background-color: blue; 47 | } 48 | -------------------------------------------------------------------------------- /apps/pages-app-dir/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. 6 | -------------------------------------------------------------------------------- /apps/pages-app-dir/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | transpilePackages: ['@workspace/ui', '@bprogress/next'], 4 | }; 5 | 6 | export default nextConfig; 7 | -------------------------------------------------------------------------------- /apps/pages-app-dir/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pages-app-dir", 3 | "version": "0.0.1", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "next dev --turbopack", 8 | "start": "next start" 9 | }, 10 | "dependencies": { 11 | "@workspace/ui": "workspace:*", 12 | "@bprogress/next": "workspace:*", 13 | "lucide-react": "0.456.0", 14 | "next-themes": "^0.4.3", 15 | "next": "^15.3.0", 16 | "react": "^19.0.0", 17 | "react-dom": "^19.0.0" 18 | }, 19 | "devDependencies": { 20 | "@types/node": "^20", 21 | "@types/react": "^19.0.1", 22 | "@types/react-dom": "^19.0.2", 23 | "@workspace/eslint-config": "workspace:^", 24 | "@workspace/typescript-config": "workspace:*", 25 | "postcss": "^8", 26 | "tailwindcss": "^3.4.1", 27 | "typescript": "^5" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /apps/pages-app-dir/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import type { AppProps } from 'next/app'; 2 | import { ProgressProvider } from '@bprogress/next/pages'; 3 | import '../globals.css'; 4 | 5 | export default function App({ Component, pageProps }: AppProps) { 6 | return ( 7 | 14 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /apps/pages-app-dir/pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import { Html, Head, Main, NextScript } from 'next/document'; 2 | 3 | export default function Document() { 4 | return ( 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /apps/pages-app-dir/pages/dashboard.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | 3 | export default function Dashboard() { 4 | return ( 5 |
6 | Home 7 |
8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /apps/pages-app-dir/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | import { useRouter } from 'next/router'; 3 | 4 | export default function Home() { 5 | const router = useRouter(); 6 | 7 | return ( 8 |
9 | Sallow 10 | Dashboard 11 | 12 |
13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /apps/pages-app-dir/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from "@workspace/ui/postcss.config"; -------------------------------------------------------------------------------- /apps/pages-app-dir/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | export * from "@workspace/ui/tailwind.config"; -------------------------------------------------------------------------------- /apps/pages-app-dir/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@workspace/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "@/*": ["./*"], 7 | "@workspace/ui/*": ["../../packages/ui/src/*"] 8 | }, 9 | "plugins": [ 10 | { 11 | "name": "next" 12 | } 13 | ] 14 | }, 15 | "include": [ 16 | "next-env.d.ts", 17 | "next.config.mjs", 18 | "**/*.ts", 19 | "**/*.tsx", 20 | ".next/types/**/*.ts" 21 | ], 22 | "exclude": ["node_modules"] 23 | } 24 | -------------------------------------------------------------------------------- /apps/remix-app/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | .env 6 | -------------------------------------------------------------------------------- /apps/remix-app/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | - 📖 [Remix docs](https://remix.run/docs) 4 | 5 | ## Development 6 | 7 | Run the dev server: 8 | 9 | ```shellscript 10 | npm run dev 11 | ``` 12 | 13 | ## Deployment 14 | 15 | First, build your app for production: 16 | 17 | ```sh 18 | npm run build 19 | ``` 20 | 21 | Then run the app in production mode: 22 | 23 | ```sh 24 | npm start 25 | ``` 26 | 27 | Now you'll need to pick a host to deploy it to. 28 | 29 | ### DIY 30 | 31 | If you're familiar with deploying Node applications, the built-in Remix app server is production-ready. 32 | 33 | Make sure to deploy the output of `npm run build` 34 | 35 | - `build/server` 36 | - `build/client` 37 | 38 | ## Styling 39 | 40 | This template comes with [Tailwind CSS](https://tailwindcss.com/) already configured for a simple default starting experience. You can use whatever css framework you prefer. See the [Vite docs on css](https://vitejs.dev/guide/features.html#css) for more information. 41 | -------------------------------------------------------------------------------- /apps/remix-app/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * By default, Remix will handle hydrating your app on the client for you. 3 | * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ 4 | * For more information, see https://remix.run/file-conventions/entry.client 5 | */ 6 | 7 | import { RemixBrowser } from '@remix-run/react'; 8 | import { startTransition, StrictMode } from 'react'; 9 | import { hydrateRoot } from 'react-dom/client'; 10 | 11 | startTransition(() => { 12 | hydrateRoot( 13 | document, 14 | 15 | 16 | , 17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /apps/remix-app/app/root.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Links, 3 | Meta, 4 | Outlet, 5 | Scripts, 6 | ScrollRestoration, 7 | } from '@remix-run/react'; 8 | import type { LinksFunction } from '@remix-run/node'; 9 | 10 | import './tailwind.css'; 11 | import { ProgressProvider } from '@bprogress/remix'; 12 | 13 | export const links: LinksFunction = () => [ 14 | { rel: 'preconnect', href: 'https://fonts.googleapis.com' }, 15 | { 16 | rel: 'preconnect', 17 | href: 'https://fonts.gstatic.com', 18 | crossOrigin: 'anonymous', 19 | }, 20 | { 21 | rel: 'stylesheet', 22 | href: 'https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap', 23 | }, 24 | ]; 25 | 26 | export function Layout({ children }: { children: React.ReactNode }) { 27 | return ( 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | {children} 38 | 39 | 40 | 41 | 42 | 43 | ); 44 | } 45 | 46 | export default function App() { 47 | return ; 48 | } 49 | -------------------------------------------------------------------------------- /apps/remix-app/app/routes/dashboard.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from '@remix-run/react'; 2 | 3 | const Dashboard = () => { 4 | return ( 5 |
6 |
7 | Profile 8 | Home 9 |
10 |
11 | ); 12 | }; 13 | 14 | export default Dashboard; 15 | -------------------------------------------------------------------------------- /apps/remix-app/app/routes/profile.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from '@remix-run/react'; 2 | 3 | const Dashboard = () => { 4 | return ( 5 |
6 |
7 | Dashboard 8 | Home 9 | 10 | Home (without progress) 11 | 12 |
13 |
14 | ); 15 | }; 16 | 17 | export default Dashboard; 18 | -------------------------------------------------------------------------------- /apps/remix-app/app/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | html, 6 | body { 7 | @apply bg-white dark:bg-gray-950; 8 | 9 | @media (prefers-color-scheme: dark) { 10 | color-scheme: dark; 11 | } 12 | } 13 | 14 | main { 15 | display: flex; 16 | flex-direction: column; 17 | } 18 | 19 | button, a { 20 | all: unset; 21 | color: white; 22 | padding: 7px 15px; 23 | cursor: pointer; 24 | border-radius: 5px; 25 | width: fit-content; 26 | margin-top: 5px; 27 | position: relative; 28 | } 29 | 30 | button:not(.default) { 31 | background-color: red; 32 | } 33 | 34 | button.default { 35 | background-color: green; 36 | } 37 | 38 | button:not(.default)::after { 39 | content: "router.push()"; 40 | } 41 | 42 | button.replace::after { 43 | content: "router.replace()" !important; 44 | } 45 | 46 | button.back::after { 47 | content: "router.back()" !important; 48 | } 49 | 50 | a::after { 51 | content: ""; 52 | } 53 | 54 | a.a::after { 55 | content: "
"; 56 | } 57 | 58 | a::after, button::after { 59 | position: absolute; 60 | color: black; 61 | margin-left: 20px; 62 | font-size: 12px; 63 | bottom: 0; 64 | } 65 | 66 | a { 67 | background-color: blue; 68 | } 69 | 70 | :root { 71 | --primary: 220 70% 50%; 72 | } 73 | -------------------------------------------------------------------------------- /apps/remix-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remix-app", 3 | "private": true, 4 | "sideEffects": false, 5 | "type": "module", 6 | "scripts": { 7 | "dev": "remix vite:dev", 8 | "start": "remix-serve ./build/server/index.js", 9 | "typecheck": "tsc" 10 | }, 11 | "dependencies": { 12 | "@remix-run/node": "^2.15.3", 13 | "@remix-run/react": "^2.15.3", 14 | "@remix-run/serve": "^2.15.3", 15 | "isbot": "^4.1.0", 16 | "react": "^18.2.0", 17 | "react-dom": "^18.2.0", 18 | "@bprogress/remix": "workspace:*" 19 | }, 20 | "devDependencies": { 21 | "@remix-run/dev": "^2.15.3", 22 | "@types/react": "^18.2.20", 23 | "@types/react-dom": "^18.2.7", 24 | "@typescript-eslint/eslint-plugin": "^6.7.4", 25 | "@typescript-eslint/parser": "^6.7.4", 26 | "autoprefixer": "^10.4.19", 27 | "eslint": "^8.38.0", 28 | "eslint-import-resolver-typescript": "^3.6.1", 29 | "eslint-plugin-import": "^2.28.1", 30 | "eslint-plugin-jsx-a11y": "^6.7.1", 31 | "eslint-plugin-react": "^7.33.2", 32 | "eslint-plugin-react-hooks": "^4.6.0", 33 | "postcss": "^8.4.38", 34 | "tailwindcss": "^3.4.4", 35 | "typescript": "^5.1.6", 36 | "vite": "^5.1.0", 37 | "vite-tsconfig-paths": "^4.2.1" 38 | }, 39 | "engines": { 40 | "node": ">=20.0.0" 41 | }, 42 | "overrides": { 43 | "react": "18.2.0", 44 | "react-dom": "18.2.0", 45 | "@types/react": "^18.2.20", 46 | "@types/react-dom": "^18.2.7" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /apps/remix-app/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /apps/remix-app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imskyleen/bprogress/f3c776a8d00cbcd55017439bf8a5053f9dbc0976/apps/remix-app/public/favicon.ico -------------------------------------------------------------------------------- /apps/remix-app/public/logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imskyleen/bprogress/f3c776a8d00cbcd55017439bf8a5053f9dbc0976/apps/remix-app/public/logo-dark.png -------------------------------------------------------------------------------- /apps/remix-app/public/logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imskyleen/bprogress/f3c776a8d00cbcd55017439bf8a5053f9dbc0976/apps/remix-app/public/logo-light.png -------------------------------------------------------------------------------- /apps/remix-app/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | export default { 4 | content: ["./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}"], 5 | theme: { 6 | extend: { 7 | fontFamily: { 8 | sans: [ 9 | "Inter", 10 | "ui-sans-serif", 11 | "system-ui", 12 | "sans-serif", 13 | "Apple Color Emoji", 14 | "Segoe UI Emoji", 15 | "Segoe UI Symbol", 16 | "Noto Color Emoji", 17 | ], 18 | }, 19 | }, 20 | }, 21 | plugins: [], 22 | } satisfies Config; 23 | -------------------------------------------------------------------------------- /apps/remix-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "**/*.ts", 4 | "**/*.tsx", 5 | "**/.server/**/*.ts", 6 | "**/.server/**/*.tsx", 7 | "**/.client/**/*.ts", 8 | "**/.client/**/*.tsx" 9 | ], 10 | "compilerOptions": { 11 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 12 | "types": ["@remix-run/node", "vite/client"], 13 | "isolatedModules": true, 14 | "esModuleInterop": true, 15 | "jsx": "react-jsx", 16 | "module": "ESNext", 17 | "moduleResolution": "Bundler", 18 | "resolveJsonModule": true, 19 | "target": "ES2022", 20 | "strict": true, 21 | "allowJs": true, 22 | "skipLibCheck": true, 23 | "forceConsistentCasingInFileNames": true, 24 | "baseUrl": ".", 25 | "paths": { 26 | "~/*": ["./app/*"] 27 | }, 28 | 29 | // Vite takes care of building everything, not tsc. 30 | "noEmit": true 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /apps/remix-app/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { vitePlugin as remix } from "@remix-run/dev"; 2 | import { defineConfig } from "vite"; 3 | import tsconfigPaths from "vite-tsconfig-paths"; 4 | 5 | declare module "@remix-run/node" { 6 | interface Future { 7 | v3_singleFetch: true; 8 | } 9 | } 10 | 11 | export default defineConfig({ 12 | plugins: [ 13 | remix({ 14 | future: { 15 | v3_fetcherPersist: true, 16 | v3_relativeSplatPath: true, 17 | v3_throwAbortReason: true, 18 | v3_singleFetch: true, 19 | v3_lazyRouteDiscovery: true, 20 | }, 21 | }), 22 | tsconfigPaths(), 23 | ], 24 | }); 25 | -------------------------------------------------------------------------------- /apps/vue-app/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue}] 2 | charset = utf-8 3 | indent_size = 2 4 | indent_style = space 5 | insert_final_newline = true 6 | trim_trailing_whitespace = true 7 | 8 | end_of_line = lf 9 | max_line_length = 100 10 | -------------------------------------------------------------------------------- /apps/vue-app/.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /apps/vue-app/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | dist 13 | dist-ssr 14 | coverage 15 | *.local 16 | 17 | /cypress/videos/ 18 | /cypress/screenshots/ 19 | 20 | # Editor directories and files 21 | .vscode/* 22 | !.vscode/extensions.json 23 | .idea 24 | *.suo 25 | *.ntvs* 26 | *.njsproj 27 | *.sln 28 | *.sw? 29 | 30 | *.tsbuildinfo 31 | -------------------------------------------------------------------------------- /apps/vue-app/.prettierrc.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "$schema": "https://json.schemastore.org/prettierrc", 4 | "semi": false, 5 | "singleQuote": true, 6 | "printWidth": 100 7 | } 8 | -------------------------------------------------------------------------------- /apps/vue-app/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "Vue.volar", 4 | "dbaeumer.vscode-eslint", 5 | "EditorConfig.EditorConfig", 6 | "esbenp.prettier-vscode" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /apps/vue-app/README.md: -------------------------------------------------------------------------------- 1 | # vue-app 2 | 3 | This template should help get you started developing with Vue 3 in Vite. 4 | 5 | ## Recommended IDE Setup 6 | 7 | [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). 8 | 9 | ## Type Support for `.vue` Imports in TS 10 | 11 | TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. 12 | 13 | ## Customize configuration 14 | 15 | See [Vite Configuration Reference](https://vite.dev/config/). 16 | 17 | ## Project Setup 18 | 19 | ```sh 20 | pnpm install 21 | ``` 22 | 23 | ### Compile and Hot-Reload for Development 24 | 25 | ```sh 26 | pnpm dev 27 | ``` 28 | 29 | ### Type-Check, Compile and Minify for Production 30 | 31 | ```sh 32 | pnpm build 33 | ``` 34 | 35 | ### Lint with [ESLint](https://eslint.org/) 36 | 37 | ```sh 38 | pnpm lint 39 | ``` 40 | -------------------------------------------------------------------------------- /apps/vue-app/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/vue-app/eslint.config.ts: -------------------------------------------------------------------------------- 1 | import pluginVue from 'eslint-plugin-vue' 2 | import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript' 3 | import skipFormatting from '@vue/eslint-config-prettier/skip-formatting' 4 | 5 | // To allow more languages other than `ts` in `.vue` files, uncomment the following lines: 6 | // import { configureVueProject } from '@vue/eslint-config-typescript' 7 | // configureVueProject({ scriptLangs: ['ts', 'tsx'] }) 8 | // More info at https://github.com/vuejs/eslint-config-typescript/#advanced-setup 9 | 10 | export default defineConfigWithVueTs( 11 | { 12 | name: 'app/files-to-lint', 13 | files: ['**/*.{ts,mts,tsx,vue}'], 14 | }, 15 | 16 | { 17 | name: 'app/files-to-ignore', 18 | ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], 19 | }, 20 | 21 | pluginVue.configs['flat/essential'], 22 | vueTsConfigs.recommended, 23 | skipFormatting, 24 | ) 25 | -------------------------------------------------------------------------------- /apps/vue-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/vue-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-app", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "preview": "vite preview", 9 | "build-only": "vite build", 10 | "type-check": "vue-tsc --build", 11 | "format": "prettier --write src/" 12 | }, 13 | "dependencies": { 14 | "vue": "^3.5.13", 15 | "vue-router": "^4.5.0", 16 | "@bprogress/vue": "workspace:*" 17 | }, 18 | "devDependencies": { 19 | "@tsconfig/node22": "^22.0.0", 20 | "@types/node": "^22.13.4", 21 | "@vitejs/plugin-vue": "^5.2.1", 22 | "@vue/eslint-config-prettier": "^10.2.0", 23 | "@vue/eslint-config-typescript": "^14.4.0", 24 | "@vue/tsconfig": "^0.7.0", 25 | "eslint": "^9.20.1", 26 | "eslint-plugin-vue": "^9.32.0", 27 | "jiti": "^2.4.2", 28 | "npm-run-all2": "^7.0.2", 29 | "prettier": "^3.5.1", 30 | "typescript": "~5.7.3", 31 | "vite": "^6.1.0", 32 | "vite-plugin-vue-devtools": "^7.7.2", 33 | "vue-tsc": "^2.2.2" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /apps/vue-app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imskyleen/bprogress/f3c776a8d00cbcd55017439bf8a5053f9dbc0976/apps/vue-app/public/favicon.ico -------------------------------------------------------------------------------- /apps/vue-app/src/Root.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | -------------------------------------------------------------------------------- /apps/vue-app/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /apps/vue-app/src/assets/main.css: -------------------------------------------------------------------------------- 1 | @import './base.css'; 2 | 3 | #app { 4 | max-width: 1280px; 5 | margin: 0 auto; 6 | padding: 2rem; 7 | font-weight: normal; 8 | } 9 | 10 | a, 11 | .green { 12 | text-decoration: none; 13 | color: hsla(160, 100%, 37%, 1); 14 | transition: 0.4s; 15 | padding: 3px; 16 | } 17 | 18 | @media (hover: hover) { 19 | a:hover { 20 | background-color: hsla(160, 100%, 37%, 0.2); 21 | } 22 | } 23 | 24 | @media (min-width: 1024px) { 25 | body { 26 | display: flex; 27 | place-items: center; 28 | } 29 | 30 | #app { 31 | display: grid; 32 | grid-template-columns: 1fr 1fr; 33 | padding: 0 2rem; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /apps/vue-app/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | 18 | 42 | -------------------------------------------------------------------------------- /apps/vue-app/src/components/ProgressBar.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 13 | -------------------------------------------------------------------------------- /apps/vue-app/src/components/WelcomeItem.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 88 | -------------------------------------------------------------------------------- /apps/vue-app/src/components/icons/IconCommunity.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /apps/vue-app/src/components/icons/IconDocumentation.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /apps/vue-app/src/components/icons/IconEcosystem.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /apps/vue-app/src/components/icons/IconSupport.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /apps/vue-app/src/components/icons/IconTooling.vue: -------------------------------------------------------------------------------- 1 | 2 | 20 | -------------------------------------------------------------------------------- /apps/vue-app/src/main.ts: -------------------------------------------------------------------------------- 1 | import './assets/main.css' 2 | 3 | import { createApp } from 'vue' 4 | import Root from './Root.vue' 5 | import router from './router' 6 | 7 | const app = createApp(Root) 8 | 9 | app.use(router) 10 | 11 | app.mount('#app') 12 | -------------------------------------------------------------------------------- /apps/vue-app/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory } from 'vue-router' 2 | import HomeView from '../views/HomeView.vue' 3 | 4 | const router = createRouter({ 5 | history: createWebHistory(import.meta.env.BASE_URL), 6 | routes: [ 7 | { 8 | path: '/', 9 | name: 'home', 10 | component: HomeView, 11 | }, 12 | { 13 | path: '/about', 14 | name: 'about', 15 | // route level code-splitting 16 | // this generates a separate chunk (About.[hash].js) for this route 17 | // which is lazy-loaded when the route is visited. 18 | component: () => import('../views/AboutView.vue'), 19 | }, 20 | ], 21 | }) 22 | 23 | export default router 24 | -------------------------------------------------------------------------------- /apps/vue-app/src/views/AboutView.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | -------------------------------------------------------------------------------- /apps/vue-app/src/views/HomeView.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /apps/vue-app/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.dom.json", 3 | "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], 4 | "exclude": ["src/**/__tests__/*"], 5 | "compilerOptions": { 6 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 7 | 8 | "paths": { 9 | "@/*": ["./src/*"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /apps/vue-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { 5 | "path": "./tsconfig.node.json" 6 | }, 7 | { 8 | "path": "./tsconfig.app.json" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /apps/vue-app/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/node22/tsconfig.json", 3 | "include": [ 4 | "vite.config.*", 5 | "vitest.config.*", 6 | "cypress.config.*", 7 | "nightwatch.conf.*", 8 | "playwright.config.*", 9 | "eslint.config.*" 10 | ], 11 | "compilerOptions": { 12 | "noEmit": true, 13 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 14 | 15 | "module": "ESNext", 16 | "moduleResolution": "Bundler", 17 | "types": ["node"] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /apps/vue-app/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url' 2 | 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | import vueDevTools from 'vite-plugin-vue-devtools' 6 | 7 | // https://vite.dev/config/ 8 | export default defineConfig({ 9 | plugins: [ 10 | vue(), 11 | vueDevTools(), 12 | ], 13 | resolve: { 14 | alias: { 15 | '@': fileURLToPath(new URL('./src', import.meta.url)) 16 | }, 17 | }, 18 | }) 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bprogress", 3 | "version": "0.0.1", 4 | "private": true, 5 | "keywords": [ 6 | "nprogress", 7 | "progress", 8 | "bar", 9 | "bprogress", 10 | "next.js", 11 | "react" 12 | ], 13 | "scripts": { 14 | "build": "turbo build", 15 | "dev": "turbo dev", 16 | "lint": "turbo lint", 17 | "test": "turbo test", 18 | "docs:dev": "pnpm pnpm --filter docs dev", 19 | "format": "prettier --write \"**/*.{ts,tsx,md}\"", 20 | "postinstall": "husky install", 21 | "prepare": "husky" 22 | }, 23 | "devDependencies": { 24 | "@workspace/eslint-config": "workspace:*", 25 | "@workspace/typescript-config": "workspace:*", 26 | "husky": "^9.1.7", 27 | "prettier": "^3.2.5", 28 | "turbo": "^2.5.0", 29 | "typescript": "5.5.4" 30 | }, 31 | "packageManager": "pnpm@9.12.3", 32 | "engines": { 33 | "node": ">=20" 34 | }, 35 | "dependencies": { 36 | "@changesets/cli": "^2.28.1" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/core/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .npmrc 3 | dist 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /packages/core/.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | !dist/ 3 | !README.md 4 | !LICENSE 5 | !package.json -------------------------------------------------------------------------------- /packages/core/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @bprogress/core 2 | 3 | ## 1.3.4 4 | 5 | ### Patch Changes 6 | 7 | - chore: change repo link 8 | 9 | ## 1.3.3 10 | 11 | ### Patch Changes 12 | 13 | - chore: add `.cjs` build 14 | 15 | ## 1.3.2 16 | 17 | ### Patch Changes 18 | 19 | - fix: force `height` and `width` to `0` in `bprogress` class 20 | 21 | ## 1.3.1 22 | 23 | ### Patch Changes 24 | 25 | - fix: update `css()` utils 26 | 27 | ## 1.3.0 28 | 29 | ### Minor Changes 30 | 31 | - feat: add indeterminate mode 32 | - feat: add `dec` and `reset` methods 33 | 34 | ## 1.2.4 35 | 36 | ### Patch Changes 37 | 38 | - feat: add iife build 39 | 40 | ## 1.2.3 41 | 42 | ### Patch Changes 43 | 44 | - fix: remove `parsePath`, `addPathPrefix` utils 45 | 46 | ## 1.2.2 47 | 48 | ### Patch Changes 49 | 50 | - feat: add `parsePath`, `addPathPrefix` and `getAnchorProperty` utils 51 | 52 | ## 1.2.1 53 | 54 | ### Patch Changes 55 | 56 | - fix: remove forgotten console.log 57 | 58 | ## 1.2.0 59 | 60 | ### Minor Changes 61 | 62 | - fix: use class selectors (`.bar`, `.spinner`) instead of role attributes for better accessibility 63 | - chore: remove CommonJS imports and switch to ESM imports with `.js` extensions 64 | -------------------------------------------------------------------------------- /packages/core/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Elliot Sutton 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/core/eslint.config.js: -------------------------------------------------------------------------------- 1 | import { config } from '@workspace/eslint-config/base'; 2 | 3 | /** @type {import("eslint").Linter.Config} */ 4 | export default config; 5 | -------------------------------------------------------------------------------- /packages/core/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { JestConfigWithTsJest } from 'ts-jest'; 2 | 3 | const config: JestConfigWithTsJest = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bprogress/core", 3 | "version": "1.3.4", 4 | "type": "module", 5 | "description": "NProgress-inspired library with more features", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/imskyleen/bprogress.git" 9 | }, 10 | "bugs": { 11 | "url": "https://github.com/imskyleen/bprogress/issues" 12 | }, 13 | "homepage": "https://bprogress.vercel.app/", 14 | "author": "Skyleen", 15 | "license": "MIT", 16 | "keywords": [ 17 | "nprogress", 18 | "progress", 19 | "bar", 20 | "bprogress" 21 | ], 22 | "main": "./dist/index.cjs", 23 | "module": "./dist/index.js", 24 | "types": "./dist/index.d.ts", 25 | "exports": { 26 | ".": { 27 | "types": "./dist/index.d.ts", 28 | "import": "./dist/index.js", 29 | "require": "./dist/index.cjs" 30 | }, 31 | "./css": "./dist/index.css" 32 | }, 33 | "files": [ 34 | "dist" 35 | ], 36 | "scripts": { 37 | "lint": "eslint . --max-warnings 0", 38 | "build": "tsup", 39 | "dev": "tsup --watch", 40 | "pub:release": "pnpm publish --no-git-checks --access public", 41 | "pub:canary": "pnpm publish --no-git-checks --tag canary --access public", 42 | "pub:beta": "pnpm publish --no-git-checks --tag beta --access public", 43 | "prepublishOnly": "pnpm test && pnpm lint && pnpm build", 44 | "test": "jest" 45 | }, 46 | "devDependencies": { 47 | "@types/jest": "^29.5.14", 48 | "@types/node": "^20.17.10", 49 | "jest": "^29.7.0", 50 | "jest-environment-jsdom": "^29.7.0", 51 | "jsdom": "^26.0.0", 52 | "ts-jest": "^29.2.5", 53 | "tsup": "^8.3.5", 54 | "typescript": "5.5.4", 55 | "eslint": "^9.19.0" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './progress'; 2 | export * from './types'; 3 | export * from './lib'; 4 | -------------------------------------------------------------------------------- /packages/core/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './css'; 2 | export * from './same-url'; 3 | export { getAnchorProperty } from './get-anchor-property'; 4 | -------------------------------------------------------------------------------- /packages/core/src/lib/same-url.ts: -------------------------------------------------------------------------------- 1 | export function isSameURL(target: URL, current: URL) { 2 | const cleanTarget = 3 | target.protocol + '//' + target.host + target.pathname + target.search; 4 | const cleanCurrent = 5 | current.protocol + '//' + current.host + current.pathname + current.search; 6 | 7 | return cleanTarget === cleanCurrent; 8 | } 9 | 10 | export function isSameURLWithoutSearch(target: URL, current: URL) { 11 | const cleanTarget = target.protocol + '//' + target.host + target.pathname; 12 | const cleanCurrent = 13 | current.protocol + '//' + current.host + current.pathname; 14 | 15 | return cleanTarget === cleanCurrent; 16 | } 17 | -------------------------------------------------------------------------------- /packages/core/src/types.ts: -------------------------------------------------------------------------------- 1 | export type BProgressDirection = 'ltr' | 'rtl'; 2 | export type BProgressPositionUsing = 3 | | 'translate3d' 4 | | 'translate' 5 | | 'margin' 6 | | 'width' 7 | | ''; 8 | 9 | export interface BProgressOptions { 10 | minimum?: number; 11 | maximum?: number; 12 | template?: string | null; 13 | easing?: string; 14 | speed?: number; 15 | trickle?: boolean; 16 | trickleSpeed?: number; 17 | showSpinner?: boolean; 18 | parent?: HTMLElement | string; 19 | positionUsing?: BProgressPositionUsing; 20 | barSelector?: string; 21 | indeterminateSelector?: string; 22 | spinnerSelector?: string; 23 | direction?: BProgressDirection; 24 | indeterminate?: boolean; 25 | } 26 | 27 | export type SpinnerPosition = 28 | | 'top-left' 29 | | 'top-right' 30 | | 'bottom-left' 31 | | 'bottom-right'; 32 | -------------------------------------------------------------------------------- /packages/core/src/utils/clamp.ts: -------------------------------------------------------------------------------- 1 | export function clamp(n: number, min: number, max: number): number { 2 | return Math.max(min, Math.min(n, max)); 3 | } 4 | -------------------------------------------------------------------------------- /packages/core/src/utils/class.ts: -------------------------------------------------------------------------------- 1 | export function addClass(element: HTMLElement, name: string): void { 2 | element.classList.add(name); 3 | } 4 | 5 | export function removeClass(element: HTMLElement, name: string): void { 6 | element.classList.remove(name); 7 | } 8 | -------------------------------------------------------------------------------- /packages/core/src/utils/element.ts: -------------------------------------------------------------------------------- 1 | export function removeElement(element: HTMLElement): void { 2 | if (element && element.parentNode) { 3 | element.parentNode.removeChild(element); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/core/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './clamp'; 2 | export * from './to-bar-perc'; 3 | export * from './to-css'; 4 | export * from './class'; 5 | export * from './element'; 6 | -------------------------------------------------------------------------------- /packages/core/src/utils/to-bar-perc.ts: -------------------------------------------------------------------------------- 1 | import type { BProgressDirection } from '../types'; 2 | 3 | export function toBarPerc(n: number, direction: BProgressDirection): number { 4 | if (direction === 'rtl') return (1 - n) * 100; 5 | return (-1 + n) * 100; 6 | } 7 | -------------------------------------------------------------------------------- /packages/core/src/utils/to-css.ts: -------------------------------------------------------------------------------- 1 | export function toCss( 2 | element: HTMLElement, 3 | properties: { [key: string]: string | undefined } | string, 4 | value?: string, 5 | ): void { 6 | if (typeof properties === 'string') { 7 | if (value !== undefined) { 8 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 9 | element.style[properties as any] = value; 10 | } 11 | } else { 12 | for (const prop in properties) { 13 | if (properties.hasOwnProperty(prop)) { 14 | const val = properties[prop]; 15 | if (val !== undefined) { 16 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 17 | element.style[prop as any] = val; 18 | } 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "declarationMap": true, 5 | "esModuleInterop": true, 6 | "incremental": false, 7 | "isolatedModules": true, 8 | "lib": ["es2022", "DOM", "DOM.Iterable"], 9 | "module": "ESNext", 10 | "moduleDetection": "force", 11 | "moduleResolution": "Node", 12 | "noUncheckedIndexedAccess": true, 13 | "resolveJsonModule": true, 14 | "skipLibCheck": true, 15 | "strict": true, 16 | "target": "ES2022", 17 | "types": ["node", "jest"], 18 | "outDir": "dist", 19 | }, 20 | "include": ["src", "__tests__"], 21 | "exclude": ["node_modules", "dist"] 22 | } 23 | -------------------------------------------------------------------------------- /packages/core/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "tsup"; 2 | import { copyFileSync } from "fs"; 3 | 4 | export default defineConfig({ 5 | entry: ["src/index.ts"], 6 | format: ["esm", "cjs", "iife"], 7 | globalName: "BProgressJS", 8 | dts: true, 9 | outDir: "dist", 10 | esbuildPlugins: [ 11 | { 12 | name: "copy-css", 13 | setup(build) { 14 | build.onEnd(() => { 15 | copyFileSync("./src/index.css", "./dist/index.css"); 16 | }); 17 | }, 18 | }, 19 | ], 20 | }); 21 | -------------------------------------------------------------------------------- /packages/eslint-config/README.md: -------------------------------------------------------------------------------- 1 | # `@workspace/eslint-config` 2 | 3 | Shared eslint configuration for the workspace. 4 | -------------------------------------------------------------------------------- /packages/eslint-config/base.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js'; 2 | import eslintConfigPrettier from 'eslint-config-prettier'; 3 | import onlyWarn from 'eslint-plugin-only-warn'; 4 | import turboPlugin from 'eslint-plugin-turbo'; 5 | import tseslint from 'typescript-eslint'; 6 | 7 | /** 8 | * A shared ESLint configuration for the repository. 9 | * 10 | * @type {import("eslint").Linter.Config} 11 | * */ 12 | export const config = [ 13 | js.configs.recommended, 14 | eslintConfigPrettier, 15 | ...tseslint.configs.recommended, 16 | { 17 | plugins: { 18 | turbo: turboPlugin, 19 | }, 20 | rules: { 21 | 'turbo/no-undeclared-env-vars': 'warn', 22 | 'no-prototype-builtins': 'off', 23 | '@typescript-eslint/no-empty-object-type': 'off', 24 | }, 25 | }, 26 | { 27 | plugins: { 28 | onlyWarn, 29 | }, 30 | }, 31 | { 32 | ignores: ['dist/**'], 33 | }, 34 | ]; 35 | -------------------------------------------------------------------------------- /packages/eslint-config/next.js: -------------------------------------------------------------------------------- 1 | import js from "@eslint/js" 2 | import pluginNext from "@next/eslint-plugin-next" 3 | import eslintConfigPrettier from "eslint-config-prettier" 4 | import pluginReact from "eslint-plugin-react" 5 | import pluginReactHooks from "eslint-plugin-react-hooks" 6 | import globals from "globals" 7 | import tseslint from "typescript-eslint" 8 | 9 | import { config as baseConfig } from "./base.js" 10 | 11 | /** 12 | * A custom ESLint configuration for libraries that use Next.js. 13 | * 14 | * @type {import("eslint").Linter.Config} 15 | * */ 16 | export const nextJsConfig = [ 17 | ...baseConfig, 18 | js.configs.recommended, 19 | eslintConfigPrettier, 20 | ...tseslint.configs.recommended, 21 | { 22 | ...pluginReact.configs.flat.recommended, 23 | languageOptions: { 24 | ...pluginReact.configs.flat.recommended.languageOptions, 25 | globals: { 26 | ...globals.serviceworker, 27 | }, 28 | }, 29 | }, 30 | { 31 | plugins: { 32 | "@next/next": pluginNext, 33 | }, 34 | rules: { 35 | ...pluginNext.configs.recommended.rules, 36 | ...pluginNext.configs["core-web-vitals"].rules, 37 | }, 38 | }, 39 | { 40 | plugins: { 41 | "react-hooks": pluginReactHooks, 42 | }, 43 | settings: { react: { version: "detect" } }, 44 | rules: { 45 | ...pluginReactHooks.configs.recommended.rules, 46 | // React scope no longer necessary with new JSX transform. 47 | "react/react-in-jsx-scope": "off", 48 | "react/prop-types": "off", 49 | }, 50 | }, 51 | ] 52 | -------------------------------------------------------------------------------- /packages/eslint-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@workspace/eslint-config", 3 | "version": "0.0.0", 4 | "type": "module", 5 | "private": true, 6 | "exports": { 7 | "./base": "./base.js", 8 | "./next-js": "./next.js", 9 | "./vue": "./vue.js", 10 | "./react-internal": "./react-internal.js" 11 | }, 12 | "devDependencies": { 13 | "@next/eslint-plugin-next": "^15.1.0", 14 | "@typescript-eslint/eslint-plugin": "^8.15.0", 15 | "@typescript-eslint/parser": "^8.25.0", 16 | "eslint": "^9.15.0", 17 | "eslint-config-prettier": "^9.1.0", 18 | "eslint-plugin-only-warn": "^1.1.0", 19 | "eslint-plugin-react": "^7.37.2", 20 | "eslint-plugin-react-hooks": "^5.0.0", 21 | "eslint-plugin-turbo": "^2.3.0", 22 | "eslint-plugin-vue": "^9.32.0", 23 | "globals": "^15.12.0", 24 | "typescript": "^5.3.3", 25 | "typescript-eslint": "^8.15.0", 26 | "vue-eslint-parser": "^9.4.3" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/eslint-config/react-internal.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js'; 2 | import eslintConfigPrettier from 'eslint-config-prettier'; 3 | import pluginReact from 'eslint-plugin-react'; 4 | import pluginReactHooks from 'eslint-plugin-react-hooks'; 5 | import globals from 'globals'; 6 | import tseslint from 'typescript-eslint'; 7 | 8 | import { config as baseConfig } from './base.js'; 9 | 10 | /** 11 | * A custom ESLint configuration for libraries that use React. 12 | * 13 | * @type {import("eslint").Linter.Config} */ 14 | export const config = [ 15 | ...baseConfig, 16 | js.configs.recommended, 17 | eslintConfigPrettier, 18 | ...tseslint.configs.recommended, 19 | pluginReact.configs.flat.recommended, 20 | { 21 | languageOptions: { 22 | ...pluginReact.configs.flat.recommended.languageOptions, 23 | globals: { 24 | ...globals.serviceworker, 25 | ...globals.browser, 26 | }, 27 | }, 28 | }, 29 | { 30 | plugins: { 31 | 'react-hooks': pluginReactHooks, 32 | }, 33 | settings: { react: { version: 'detect' } }, 34 | rules: { 35 | ...pluginReactHooks.configs.recommended.rules, 36 | // React scope no longer necessary with new JSX transform. 37 | 'react/react-in-jsx-scope': 'off', 38 | 'react/prop-types': 'off', 39 | '@typescript-eslint/no-empty-object-type': 'off', 40 | }, 41 | }, 42 | ]; 43 | -------------------------------------------------------------------------------- /packages/eslint-config/vue.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js'; 2 | import eslintConfigPrettier from 'eslint-config-prettier'; 3 | import pluginVue from 'eslint-plugin-vue'; 4 | import globals from 'globals'; 5 | import tseslint from 'typescript-eslint'; 6 | 7 | import { config as baseConfig } from './base.js'; 8 | 9 | /** 10 | * A custom ESLint configuration for Vue 11 | * 12 | * @type {import("eslint").Linter.Config[]} 13 | */ 14 | export const config = [ 15 | ...baseConfig, 16 | js.configs.recommended, 17 | eslintConfigPrettier, 18 | ...tseslint.configs.recommended, 19 | ...pluginVue.configs['flat/recommended'], 20 | { 21 | files: ['**/*.vue'], 22 | languageOptions: { 23 | parser: await import('vue-eslint-parser'), 24 | parserOptions: { 25 | ecmaVersion: 'latest', 26 | sourceType: 'module', 27 | extraFileExtensions: ['.vue'], 28 | parser: await import('@typescript-eslint/parser'), 29 | }, 30 | globals: { 31 | ...globals.serviceworker, 32 | ...globals.browser, 33 | }, 34 | }, 35 | }, 36 | { 37 | plugins: { 38 | vue: pluginVue, 39 | }, 40 | settings: { 41 | vue: { 42 | version: '3', 43 | }, 44 | }, 45 | rules: { 46 | ...pluginVue.configs.recommended.rules, 47 | 'vue/multi-word-component-names': 'off', 48 | 'vue/no-v-html': 'off', 49 | 'vue/max-attributes-per-line': 'off', 50 | '@typescript-eslint/no-empty-object-type': 'off', 51 | }, 52 | }, 53 | ]; 54 | 55 | export default config; 56 | -------------------------------------------------------------------------------- /packages/next/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .npmrc 3 | .DS_Store -------------------------------------------------------------------------------- /packages/next/.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | !dist/ 3 | !README.md 4 | !LICENSE 5 | !package.json -------------------------------------------------------------------------------- /packages/next/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Elliot Sutton 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/next/eslint.config.js: -------------------------------------------------------------------------------- 1 | import { config } from '@workspace/eslint-config/react-internal'; 2 | 3 | /** @type {import("eslint").Linter.Config} */ 4 | export default config; 5 | -------------------------------------------------------------------------------- /packages/next/src/app.ts: -------------------------------------------------------------------------------- 1 | export { useRouter } from "./hooks/use-router"; 2 | export { AppProgressProvider as ProgressProvider } from "./providers/app-progress-provider"; 3 | -------------------------------------------------------------------------------- /packages/next/src/components/app-progress.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | useAnchorProgress, 3 | withMemo, 4 | type AnchorProgressProps, 5 | } from '@bprogress/react'; 6 | import { usePathname, useSearchParams } from 'next/navigation.js'; 7 | 8 | const AppProgressComponent = (props: AnchorProgressProps) => { 9 | const pathname = usePathname(); 10 | const searchParams = useSearchParams(); 11 | 12 | useAnchorProgress(props, [pathname, searchParams]); 13 | 14 | return null; 15 | }; 16 | 17 | export const AppProgress = withMemo(AppProgressComponent); 18 | 19 | AppProgress.displayName = 'AppProgress'; 20 | -------------------------------------------------------------------------------- /packages/next/src/components/pages-progress.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | import { isSameURL, isSameURLWithoutSearch } from '@bprogress/core'; 3 | import { RouterProgressProps, useProgress, withMemo } from '@bprogress/react'; 4 | import Router from 'next/router.js'; 5 | 6 | const PagesProgressComponent = ({ 7 | shallowRouting = false, 8 | disableSameURL = true, 9 | startPosition = 0, 10 | delay = 0, 11 | stopDelay = 0, 12 | }: RouterProgressProps) => { 13 | const { start, stop } = useProgress(); 14 | 15 | useEffect(() => { 16 | const handleRouteStart = (url: string) => { 17 | const targetUrl = new URL(url, location.href); 18 | const currentUrl = new URL(location.href); 19 | 20 | if ( 21 | shallowRouting && 22 | isSameURLWithoutSearch(targetUrl, currentUrl) && 23 | disableSameURL 24 | ) 25 | return; 26 | 27 | // If the URL is the same, we don't want to start the progress bar 28 | if (isSameURL(targetUrl, currentUrl) && disableSameURL) return; 29 | 30 | start(startPosition, delay); 31 | }; 32 | 33 | const handleRouteDone = () => stop(stopDelay); 34 | 35 | Router.events.on('routeChangeStart', handleRouteStart); 36 | Router.events.on('routeChangeComplete', handleRouteDone); 37 | Router.events.on('routeChangeError', handleRouteDone); 38 | 39 | return () => { 40 | // Make sure to remove the event handler on unmount! 41 | Router.events.off('routeChangeStart', handleRouteStart); 42 | Router.events.off('routeChangeComplete', handleRouteDone); 43 | Router.events.off('routeChangeError', handleRouteDone); 44 | }; 45 | // eslint-disable-next-line react-hooks/exhaustive-deps 46 | }, []); 47 | 48 | return null; 49 | }; 50 | 51 | export const PagesProgress = withMemo(PagesProgressComponent); 52 | 53 | PagesProgress.displayName = 'PagesProgress'; 54 | -------------------------------------------------------------------------------- /packages/next/src/index.ts: -------------------------------------------------------------------------------- 1 | export { useRouter } from "./hooks/use-router"; 2 | export { AppProgressProvider } from "./providers/app-progress-provider"; 3 | export { PagesProgressProvider } from "./providers/pages-progress-provider"; 4 | export { 5 | useProgress, 6 | Progress, 7 | Bar, 8 | Peg, 9 | Spinner, 10 | SpinnerIcon, 11 | Indeterminate, 12 | } from "@bprogress/react"; 13 | export type { 14 | SpinnerPosition, 15 | ProgressContextValue, 16 | ProgressComponentProps, 17 | ProgressProps, 18 | BarProps, 19 | PegProps, 20 | SpinnerProps, 21 | SpinnerIconProps, 22 | IndeterminateProps, 23 | } from "@bprogress/react"; 24 | export type * from "./types"; 25 | export type { BProgressOptions } from "@bprogress/core"; 26 | -------------------------------------------------------------------------------- /packages/next/src/pages.ts: -------------------------------------------------------------------------------- 1 | export { PagesProgressProvider as ProgressProvider } from "./providers/pages-progress-provider"; 2 | -------------------------------------------------------------------------------- /packages/next/src/providers/app-progress-provider.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { AppProgressProps, AppProgressProviderProps } from '../types'; 3 | import { AppProgress } from '../components/app-progress'; 4 | import { withSuspense } from '@bprogress/react'; 5 | import { NextProgressProvider } from './next-progress-provider'; 6 | 7 | const SuspendedAppProgress = withSuspense(AppProgress); 8 | 9 | export const AppProgressProvider = ({ 10 | children, 11 | ...props 12 | }: AppProgressProviderProps) => { 13 | return ( 14 | 15 | {children} 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/next/src/providers/next-progress-provider.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | AnchorProgressProps, 4 | ProgressProvider, 5 | ProgressProviderProps, 6 | RouterProgressProps, 7 | } from '@bprogress/react'; 8 | 9 | export interface NextProgressProviderComponentProps 10 | extends ProgressProviderProps { 11 | ProgressComponent: React.ComponentType< 12 | RouterProgressProps | AnchorProgressProps 13 | >; 14 | } 15 | 16 | export const NextProgressProvider = ({ 17 | children, 18 | ProgressComponent, 19 | color, 20 | height, 21 | options, 22 | spinnerPosition, 23 | style, 24 | disableStyle, 25 | nonce, 26 | stopDelay, 27 | delay, 28 | startPosition, 29 | disableSameURL, 30 | shallowRouting, 31 | ...props 32 | }: NextProgressProviderComponentProps) => { 33 | return ( 34 | 48 | 56 | {children} 57 | 58 | ); 59 | }; 60 | -------------------------------------------------------------------------------- /packages/next/src/providers/pages-progress-provider.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { PagesProgressProviderProps } from '../types'; 3 | import { PagesProgress } from '../components/pages-progress'; 4 | import { NextProgressProvider } from './next-progress-provider'; 5 | 6 | export const PagesProgressProvider = ({ 7 | children, 8 | ...props 9 | }: PagesProgressProviderProps) => { 10 | return ( 11 | 12 | {children} 13 | 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /packages/next/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "dist", 4 | "module": "esnext", 5 | "target": "es5", 6 | "lib": ["es6", "dom", "es2016", "es2017"], 7 | "sourceMap": true, 8 | "allowJs": false, 9 | "jsx": "react", 10 | "allowSyntheticDefaultImports": true, 11 | "declaration": true, 12 | "moduleResolution": "node", 13 | "forceConsistentCasingInFileNames": true, 14 | "noImplicitReturns": true, 15 | "noImplicitThis": true, 16 | "noImplicitAny": true, 17 | "strictNullChecks": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | }, 21 | "include": ["src"], 22 | "exclude": ["node_modules", "dist", "example", "tsup.config.js"] 23 | } -------------------------------------------------------------------------------- /packages/next/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "tsup"; 2 | 3 | export default defineConfig({ 4 | entry: ["src/index.ts", "src/app.ts", "src/pages.ts"], 5 | sourcemap: true, 6 | clean: true, 7 | dts: true, 8 | splitting: false, 9 | format: ["esm", "cjs"], 10 | external: [ 11 | "react", 12 | "react-dom", 13 | "next/router", 14 | "next/navigation", 15 | "@bprogress/react", 16 | "@bprogress/core", 17 | ], 18 | }); 19 | -------------------------------------------------------------------------------- /packages/react/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .npmrc 3 | .DS_Store -------------------------------------------------------------------------------- /packages/react/.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | !dist/ 3 | !README.md 4 | !LICENSE 5 | !package.json -------------------------------------------------------------------------------- /packages/react/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @bprogress/react 2 | 3 | ## 1.2.7 4 | 5 | ### Patch Changes 6 | 7 | - chore: change repo link 8 | - chore: upgrade to `@bprogress/core@1.3.4` 9 | 10 | ## 1.2.6 11 | 12 | ### Patch Changes 13 | 14 | - feat: add `disableSameURL`, `startPosition`, `delay` and `stopDelay` to ProgressProvider 15 | 16 | ## 1.2.5 17 | 18 | ### Patch Changes 19 | 20 | - feat: add auto stop control 21 | 22 | ## 1.2.4 23 | 24 | ### Patch Changes 25 | 26 | - chore: add `.cjs` build 27 | - chore: upgrade to `@bprogress/core@1.3.3` 28 | 29 | ## 1.2.3 30 | 31 | ### Patch Changes 32 | 33 | - chore: upgrade to `@bprogress/core@1.3.2` 34 | 35 | ## 1.2.2 36 | 37 | ### Patch Changes 38 | 39 | - fix: prevent progress when the link has a `download` attribute 40 | 41 | ## 1.2.1 42 | 43 | ### Patch Changes 44 | 45 | - chore: upgrade to `@bprogress/core@1.3.1` 46 | 47 | ## 1.2.0 48 | 49 | ### Minor Changes 50 | 51 | - feat: add `dec` method to `ProgressProvider` 52 | - feat: add `Indeterminate` component 53 | - chore: upgrade to `@bprogress/core@1.3.0` 54 | 55 | ## 1.1.8 56 | 57 | ### Patch Changes 58 | 59 | - chore: improve `package.json` description 60 | 61 | ## 1.1.7 62 | 63 | ### Patch Changes 64 | 65 | - chore: upgrade to `@bprogress/core@1.2.3` 66 | 67 | ## 1.1.6 68 | 69 | ### Patch Changes 70 | 71 | - chore: upgrade to `@bprogress/core@1.2.1` 72 | 73 | ## 1.1.5 74 | 75 | ### Patch Changes 76 | 77 | - chore: upgrade to `@bprogress/core@1.2.0` 78 | - fix: remove role attributes from bar and spinner components 79 | -------------------------------------------------------------------------------- /packages/react/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Elliot Sutton 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/react/__tests__/utils/classnames.test.ts: -------------------------------------------------------------------------------- 1 | import { classNames } from '../../src/utils/classnames'; 2 | 3 | describe('classNames', () => { 4 | it('returns an empty string when called with no arguments', () => { 5 | expect(classNames()).toBe(''); 6 | }); 7 | 8 | it('returns the single class name when called with one argument', () => { 9 | expect(classNames('foo')).toBe('foo'); 10 | }); 11 | 12 | it('joins multiple class names with a space', () => { 13 | expect(classNames('foo', 'bar', 'baz')).toBe('foo bar baz'); 14 | }); 15 | 16 | it('ignores falsy values (undefined, null, false)', () => { 17 | expect(classNames('foo', undefined, null, false, 'bar')).toBe('foo bar'); 18 | }); 19 | 20 | it('ignores empty strings and joins the rest with spaces', () => { 21 | expect(classNames('foo', '', 'bar')).toBe('foo bar'); 22 | }); 23 | 24 | it('works with a combination of valid and invalid values', () => { 25 | expect(classNames('', 'foo', null, 'bar', undefined, false, 'baz')).toBe( 26 | 'foo bar baz', 27 | ); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /packages/react/__tests__/utils/with-suspense.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, screen } from '@testing-library/react'; 3 | import { withSuspense } from '../../src/utils/with-suspense'; 4 | 5 | describe('withSuspense', () => { 6 | it('renders the wrapped component correctly', async () => { 7 | // Dummy component for testing 8 | const Dummy: React.FC<{ message: string }> = ({ message }) => { 9 | return
{message}
; 10 | }; 11 | 12 | // Wrap the Dummy component with withSuspense 13 | const WrappedDummy = withSuspense(Dummy); 14 | 15 | // Render the wrapped component 16 | render(); 17 | 18 | // Verify that the Dummy component's content is rendered 19 | expect(screen.getByText('Test Message')).toBeInTheDocument(); 20 | }); 21 | 22 | it('renders a lazy component wrapped with Suspense', async () => { 23 | // Create a lazy component that simulates dynamic import 24 | const LazyComponent = React.lazy(() => 25 | Promise.resolve({ 26 | default: ({ message }: { message: string }) =>
{message}
, 27 | }), 28 | ); 29 | 30 | // Wrap the lazy component with withSuspense 31 | const WrappedLazy = withSuspense(LazyComponent); 32 | 33 | // Render the wrapped lazy component 34 | render(); 35 | 36 | // Since the lazy component resolves immediately, verify its content is eventually rendered 37 | expect( 38 | await screen.findByText('Lazy Component Loaded'), 39 | ).toBeInTheDocument(); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /packages/react/eslint.config.js: -------------------------------------------------------------------------------- 1 | import { config } from "@workspace/eslint-config/react-internal" 2 | 3 | /** @type {import("eslint").Linter.Config} */ 4 | export default config 5 | -------------------------------------------------------------------------------- /packages/react/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { JestConfigWithTsJest } from 'ts-jest'; 2 | 3 | const config: JestConfigWithTsJest = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | moduleNameMapper: { 7 | '\\.(css|less|scss|sass)$': 'identity-obj-proxy', 8 | }, 9 | transform: { 10 | '^.+\\.tsx?$': 'ts-jest', 11 | }, 12 | setupFilesAfterEnv: ['/jest.setup.ts'], 13 | silent: true, 14 | }; 15 | 16 | export default config; 17 | -------------------------------------------------------------------------------- /packages/react/jest.setup.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/bar.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { ProgressComponentProps } from '../types'; 3 | import { classNames } from '../utils/classnames'; 4 | 5 | export type BarProps = 6 | ProgressComponentProps; 7 | 8 | function BarInner( 9 | { as, children, className, classSelector = 'bar', ...rest }: BarProps, 10 | ref: React.ForwardedRef>, 11 | ) { 12 | const Component = as ?? ('div' as T); 13 | return React.createElement( 14 | Component, 15 | { 16 | ref, 17 | className: classNames(classSelector, className), 18 | ...(rest as React.ComponentPropsWithoutRef), 19 | }, 20 | children, 21 | ); 22 | } 23 | 24 | export const Bar = React.forwardRef(BarInner) as < 25 | T extends React.ElementType = 'div', 26 | >( 27 | props: BarProps & { ref?: React.ForwardedRef> }, 28 | ) => ReturnType; 29 | -------------------------------------------------------------------------------- /packages/react/src/components/indeterminate.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { ProgressComponentProps } from '../types'; 3 | import { classNames } from '../utils/classnames'; 4 | 5 | export type IndeterminateProps = 6 | ProgressComponentProps & { children?: never }; 7 | 8 | function IndeterminateInner( 9 | { 10 | as, 11 | className, 12 | classSelector = 'indeterminate', 13 | ...rest 14 | }: IndeterminateProps, 15 | ref: React.ForwardedRef>, 16 | ) { 17 | const Component = as ?? ('div' as T); 18 | return React.createElement( 19 | Component, 20 | { 21 | ref, 22 | className: classNames(classSelector, className), 23 | ...(rest as React.ComponentPropsWithoutRef), 24 | }, 25 | React.createElement('div', { className: 'inc' }), 26 | React.createElement('div', { className: 'dec' }), 27 | ); 28 | } 29 | 30 | export const Indeterminate = React.forwardRef(IndeterminateInner) as < 31 | T extends React.ElementType = 'div', 32 | >( 33 | props: IndeterminateProps & { 34 | ref?: React.ForwardedRef>; 35 | }, 36 | ) => ReturnType; 37 | -------------------------------------------------------------------------------- /packages/react/src/components/index.tsx: -------------------------------------------------------------------------------- 1 | export { Progress, type ProgressProps } from './progress'; 2 | export { Bar, type BarProps } from './bar'; 3 | export { Peg, type PegProps } from './peg'; 4 | export { Spinner, type SpinnerProps } from './spinner'; 5 | export { SpinnerIcon, type SpinnerIconProps } from './spinner-icon'; 6 | export { Indeterminate, type IndeterminateProps } from './indeterminate'; 7 | -------------------------------------------------------------------------------- /packages/react/src/components/peg.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { ProgressComponentProps } from '../types'; 3 | import { classNames } from '../utils/classnames'; 4 | 5 | export type PegProps = Omit< 6 | ProgressComponentProps, 7 | 'classSelector' 8 | > & { 9 | classSelector?: string; 10 | }; 11 | 12 | function PegInner( 13 | { as, children, className, classSelector = 'peg', ...rest }: PegProps, 14 | ref: React.ForwardedRef>, 15 | ) { 16 | const Component = as ?? ('div' as T); 17 | return React.createElement( 18 | Component, 19 | { 20 | ref, 21 | className: classNames(classSelector, className), 22 | ...(rest as React.ComponentPropsWithoutRef), 23 | }, 24 | children, 25 | ); 26 | } 27 | 28 | export const Peg = React.forwardRef(PegInner) as < 29 | T extends React.ElementType = 'div', 30 | >( 31 | props: PegProps & { ref?: React.ForwardedRef> }, 32 | ) => ReturnType; 33 | -------------------------------------------------------------------------------- /packages/react/src/components/progress.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { ProgressComponentProps } from '../types'; 3 | import { classNames } from '../utils/classnames'; 4 | import { Bar } from './bar'; 5 | import { Peg } from './peg'; 6 | import { Spinner } from './spinner'; 7 | import { SpinnerIcon } from './spinner-icon'; 8 | 9 | export type ProgressProps = Omit< 10 | ProgressComponentProps, 11 | 'classSelector' 12 | >; 13 | 14 | function ProgressInner( 15 | { as, children, className, style, ...rest }: ProgressProps, 16 | ref: React.ForwardedRef>, 17 | ) { 18 | const Component = as ?? ('div' as T); 19 | return React.createElement( 20 | Component, 21 | { 22 | ref, 23 | className: classNames('bprogress', className), 24 | style: { ...style, display: 'none' } as React.CSSProperties, 25 | ...(rest as React.ComponentPropsWithoutRef), 26 | }, 27 | children || ( 28 | <> 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | ), 37 | ); 38 | } 39 | 40 | export const Progress = React.forwardRef(ProgressInner) as < 41 | T extends React.ElementType = 'div', 42 | >( 43 | props: ProgressProps & { ref?: React.ForwardedRef> }, 44 | ) => ReturnType; 45 | -------------------------------------------------------------------------------- /packages/react/src/components/spinner-icon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { ProgressComponentProps } from '../types'; 3 | import { classNames } from '../utils/classnames'; 4 | 5 | export type SpinnerIconProps = Omit< 6 | ProgressComponentProps, 7 | 'classSelector' 8 | > & { 9 | classSelector?: string; 10 | }; 11 | 12 | function SpinnerIconInner( 13 | { 14 | as, 15 | children, 16 | className, 17 | classSelector = 'spinner-icon', 18 | ...rest 19 | }: SpinnerIconProps, 20 | ref: React.ForwardedRef>, 21 | ) { 22 | const Component = as ?? ('div' as T); 23 | return React.createElement( 24 | Component, 25 | { 26 | ref, 27 | className: classNames(classSelector, className), 28 | ...(rest as React.ComponentPropsWithoutRef), 29 | }, 30 | children, 31 | ); 32 | } 33 | 34 | export const SpinnerIcon = React.forwardRef(SpinnerIconInner) as < 35 | T extends React.ElementType = 'div', 36 | >( 37 | props: SpinnerIconProps & { 38 | ref?: React.ForwardedRef>; 39 | }, 40 | ) => ReturnType; 41 | -------------------------------------------------------------------------------- /packages/react/src/components/spinner.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import type { ProgressComponentProps } from '../types'; 3 | import { classNames } from '../utils/classnames'; 4 | 5 | export type SpinnerProps = 6 | ProgressComponentProps; 7 | 8 | function SpinnerInner( 9 | { 10 | as, 11 | children, 12 | className, 13 | classSelector = 'spinner', 14 | ...rest 15 | }: SpinnerProps, 16 | ref: React.ForwardedRef>, 17 | ) { 18 | const Component = as ?? ('div' as T); 19 | return React.createElement( 20 | Component, 21 | { 22 | ref, 23 | className: classNames(classSelector, className), 24 | ...(rest as React.ComponentPropsWithoutRef), 25 | }, 26 | children, 27 | ); 28 | } 29 | 30 | export const Spinner = React.forwardRef(SpinnerInner) as < 31 | T extends React.ElementType = 'div', 32 | >( 33 | props: SpinnerProps & { ref?: React.ForwardedRef> }, 34 | ) => ReturnType; 35 | -------------------------------------------------------------------------------- /packages/react/src/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './providers/progress-provider'; 2 | export * from './hooks/use-anchor-progress'; 3 | export * from './components'; 4 | export * from './utils'; 5 | export type * from './types'; 6 | export type { BProgressOptions, SpinnerPosition } from '@bprogress/core'; 7 | -------------------------------------------------------------------------------- /packages/react/src/utils/classnames.ts: -------------------------------------------------------------------------------- 1 | export function classNames( 2 | ...classes: (string | undefined | null | false)[] 3 | ): string { 4 | return classes.filter(Boolean).join(' '); 5 | } 6 | -------------------------------------------------------------------------------- /packages/react/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './with-suspense'; 2 | export { withMemo } from './with-memo'; 3 | -------------------------------------------------------------------------------- /packages/react/src/utils/with-memo.tsx: -------------------------------------------------------------------------------- 1 | import React, { memo } from 'react'; 2 | 3 | export function shallowCompareProps( 4 | prevProps: T, 5 | nextProps: T, 6 | ignoreKeys: string[] = [], 7 | ): boolean { 8 | const prevKeys = Object.keys(prevProps).filter( 9 | (key) => !ignoreKeys.includes(key), 10 | ); 11 | const nextKeys = Object.keys(nextProps).filter( 12 | (key) => !ignoreKeys.includes(key), 13 | ); 14 | 15 | if (prevKeys.length !== nextKeys.length) { 16 | return false; 17 | } 18 | 19 | for (const key of prevKeys) { 20 | if (prevProps[key as keyof T] !== nextProps[key as keyof T]) { 21 | return false; 22 | } 23 | } 24 | return true; 25 | } 26 | 27 | export function withMemo< 28 | P extends { memo?: boolean; shouldCompareComplexProps?: boolean }, 29 | >( 30 | Component: React.ComponentType

, 31 | ignoreKeys: string[] = ['memo', 'shouldCompareComplexProps'], 32 | ) { 33 | return memo(Component, (prevProps, nextProps) => { 34 | if (nextProps.memo === false) return false; 35 | if (!nextProps.shouldCompareComplexProps) return true; 36 | return shallowCompareProps(prevProps, nextProps, ignoreKeys); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /packages/react/src/utils/with-suspense.tsx: -------------------------------------------------------------------------------- 1 | import React, { ComponentType, Suspense } from 'react'; 2 | 3 | export function withSuspense

(Component: ComponentType

) { 4 | return function WithSuspenseComponent(props: P) { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /packages/react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "dist", 4 | "module": "esnext", 5 | "target": "es5", 6 | "lib": ["es6", "dom", "es2016", "es2017"], 7 | "sourceMap": true, 8 | "allowJs": false, 9 | "jsx": "react", 10 | "allowSyntheticDefaultImports": true, 11 | "declaration": true, 12 | "moduleResolution": "node", 13 | "forceConsistentCasingInFileNames": true, 14 | "noImplicitReturns": true, 15 | "noImplicitThis": true, 16 | "noImplicitAny": true, 17 | "strictNullChecks": true, 18 | "esModuleInterop": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "types": ["jest", "@testing-library/jest-dom", "node"] 22 | }, 23 | "include": ["src", "__tests__"], 24 | "exclude": ["node_modules", "dist", "example", "tsup.config.js"] 25 | } -------------------------------------------------------------------------------- /packages/react/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "tsup"; 2 | 3 | export default defineConfig({ 4 | entry: ["src/index.tsx"], 5 | sourcemap: true, 6 | clean: true, 7 | dts: true, 8 | format: ["esm", "cjs"], 9 | external: ["react", "react-dom", "@bprogress/core"], 10 | }); 11 | -------------------------------------------------------------------------------- /packages/remix/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .npmrc 3 | .DS_Store -------------------------------------------------------------------------------- /packages/remix/.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | !dist/ 3 | !README.md 4 | !LICENSE 5 | !package.json -------------------------------------------------------------------------------- /packages/remix/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @bprogress/remix 2 | 3 | ## 1.0.19 4 | 5 | ### Patch Changes 6 | 7 | - chore: change repo link 8 | - chore: upgrade to `@bprogress/core@1.3.4` 9 | - chore: upgrade to `@bprogress/react@1.2.7` 10 | 11 | ## 1.0.18 12 | 13 | ### Patch Changes 14 | 15 | - chore: upgrade to `@bprogress/react@1.2.6` 16 | - add `delay` and `stopDelay` options to router options 17 | - use `disableSameURL`, `startPosition`, `delay` and `stopDelay` from the Provider props by default 18 | 19 | ## 1.0.17 20 | 21 | ### Patch Changes 22 | 23 | - chore: upgrade to `@bprogress/react@1.2.5` 24 | 25 | ## 1.0.16 26 | 27 | ### Patch Changes 28 | 29 | - chore: add `.cjs` build 30 | - chore: upgrade to `@bprogress/core@1.3.3` and `@bprogress/react@1.2.4` 31 | 32 | ## 1.0.15 33 | 34 | ### Patch Changes 35 | 36 | - chore: upgrade to `@bprogress/core@1.3.2` and `@bprogress/react@1.2.3` 37 | 38 | ## 1.0.14 39 | 40 | ### Patch Changes 41 | 42 | - chore: upgrade to `@bprogress/react@1.2.2` 43 | 44 | ## 1.0.13 45 | 46 | ### Patch Changes 47 | 48 | - chore: upgrade to `@bprogress/core@1.3.1` and `@bprogress/react@1.2.1` 49 | 50 | ## 1.0.12 51 | 52 | ### Patch Changes 53 | 54 | - chore: upgrade to `@bprogress/core@1.3.0` and `@bprogress/react@1.2.0` 55 | 56 | ## 1.0.10 57 | 58 | ### Patch Changes 59 | 60 | - chore: improve `package.json` description 61 | 62 | ## 1.0.9 63 | 64 | ### Patch Changes 65 | 66 | - chore: upgrade to `@bprogress/core@1.2.3` and `@bprogress/react@1.1.7` 67 | 68 | ## 1.0.8 69 | 70 | ### Patch Changes 71 | 72 | - chore: upgrade to `@bprogress/core@1.2.1` and `@bprogress/react@1.1.6` 73 | 74 | ## 1.0.7 75 | 76 | ### Patch Changes 77 | 78 | - chore: upgrade to `@bprogress/core@1.2.0` and `@bprogress/react@1.1.5` 79 | -------------------------------------------------------------------------------- /packages/remix/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Elliot Sutton 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/remix/eslint.config.js: -------------------------------------------------------------------------------- 1 | import { config } from "@workspace/eslint-config/react-internal" 2 | 3 | /** @type {import("eslint").Linter.Config} */ 4 | export default config 5 | -------------------------------------------------------------------------------- /packages/remix/src/components/remix-progress.tsx: -------------------------------------------------------------------------------- 1 | import { useLocation } from '@remix-run/react'; 2 | import { useAnchorProgress, withMemo } from '@bprogress/react'; 3 | import type { RemixProgressProps } from '../types'; 4 | 5 | const RemixProgressComponent = (props: RemixProgressProps) => { 6 | const routerLocation = useLocation(); 7 | 8 | useAnchorProgress( 9 | { 10 | ...props, 11 | forcedStopDelay: 500, 12 | }, 13 | [routerLocation], 14 | ); 15 | 16 | return null; 17 | }; 18 | 19 | export const RemixProgress = withMemo(RemixProgressComponent); 20 | 21 | RemixProgress.displayName = 'RemixProgress'; 22 | -------------------------------------------------------------------------------- /packages/remix/src/index.tsx: -------------------------------------------------------------------------------- 1 | export { RemixProgressProvider as ProgressProvider } from './providers/remix-progress-provider'; 2 | export { 3 | useProgress, 4 | Progress, 5 | Bar, 6 | Peg, 7 | Spinner, 8 | SpinnerIcon, 9 | Indeterminate, 10 | } from '@bprogress/react'; 11 | export * from './hooks/use-navigate'; 12 | export type { 13 | SpinnerPosition, 14 | ProgressContextValue, 15 | ProgressComponentProps, 16 | ProgressProps, 17 | BarProps, 18 | PegProps, 19 | SpinnerProps, 20 | SpinnerIconProps, 21 | IndeterminateProps, 22 | } from '@bprogress/react'; 23 | export type * from './types'; 24 | export type { BProgressOptions } from '@bprogress/core'; 25 | -------------------------------------------------------------------------------- /packages/remix/src/providers/remix-progress-provider.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ProgressProvider } from '@bprogress/react'; 3 | import { RemixProgress } from '../components/remix-progress'; 4 | import type { RemixProgressProviderProps } from '../types'; 5 | 6 | export const RemixProgressProvider = ({ 7 | children, 8 | color, 9 | height, 10 | options, 11 | spinnerPosition, 12 | style, 13 | disableStyle, 14 | nonce, 15 | ...props 16 | }: RemixProgressProviderProps) => { 17 | return ( 18 | 27 | 28 | {children} 29 | 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /packages/remix/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | AnchorProgressProps, 3 | AnchorProgressProviderProps, 4 | } from '@bprogress/react'; 5 | import type { NavigateFunction, Path } from '@remix-run/react'; 6 | 7 | export interface RemixProgressProps extends AnchorProgressProps {} 8 | export interface RemixProgressProviderProps 9 | extends AnchorProgressProviderProps {} 10 | 11 | /** 12 | * @param showProgress Show the progress bar. @default true 13 | * @param startPosition The position of the progress bar at the start of the page load - @default 0 14 | * @param disableSameURL Disable triggering progress bar on the same URL - @default true 15 | */ 16 | export interface NavigateActionsProgressOptions { 17 | showProgress?: boolean; 18 | startPosition?: number; 19 | disableSameURL?: boolean; 20 | delay?: number; 21 | stopDelay?: number; 22 | } 23 | 24 | /** 25 | * @param customNavigate Custom navigate - @default undefined 26 | */ 27 | export interface NavigateProgressOptions 28 | extends NavigateActionsProgressOptions { 29 | customNavigate?: () => NavigateFunction; 30 | } 31 | 32 | // We need to copy the NavigateOptions type from Remix's source code 33 | // because it's not exported in the package's public API. 34 | type NavigateOptions = { 35 | replace?: boolean; 36 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 37 | state?: any; 38 | preventScrollReset?: boolean; 39 | relative?: 'route' | 'path'; 40 | flushSync?: boolean; 41 | viewTransition?: boolean; 42 | }; 43 | 44 | type To = string | Partial; 45 | 46 | // Enhanced NavigateFunction that supports progress options. 47 | export interface ProgressNavigateFunction { 48 | ( 49 | to: To, 50 | options?: NavigateOptions, 51 | progressOptions?: NavigateActionsProgressOptions, 52 | ): void; 53 | (delta: number, progressOptions?: NavigateActionsProgressOptions): void; 54 | } 55 | -------------------------------------------------------------------------------- /packages/remix/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "dist", 4 | "module": "esnext", 5 | "target": "es5", 6 | "lib": ["es6", "dom", "es2016", "es2017"], 7 | "sourceMap": true, 8 | "allowJs": false, 9 | "jsx": "react", 10 | "allowSyntheticDefaultImports": true, 11 | "declaration": true, 12 | "moduleResolution": "node", 13 | "forceConsistentCasingInFileNames": true, 14 | "noImplicitReturns": true, 15 | "noImplicitThis": true, 16 | "noImplicitAny": true, 17 | "strictNullChecks": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true 20 | }, 21 | "include": ["src"], 22 | "exclude": ["node_modules", "dist", "example", "tsup.config.js"] 23 | } -------------------------------------------------------------------------------- /packages/remix/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "tsup"; 2 | 3 | export default defineConfig({ 4 | entry: ["src/index.tsx"], 5 | sourcemap: true, 6 | clean: true, 7 | dts: true, 8 | format: ["esm", "cjs"], 9 | external: [ 10 | "react", 11 | "react-dom", 12 | "@remix-run/react", 13 | "@bprogress/core", 14 | "@bprogress/react", 15 | ], 16 | }); 17 | -------------------------------------------------------------------------------- /packages/typescript-config/README.md: -------------------------------------------------------------------------------- 1 | # `@workspace/typescript-config` 2 | 3 | Shared typescript configuration for the workspace. 4 | -------------------------------------------------------------------------------- /packages/typescript-config/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Default", 4 | "compilerOptions": { 5 | "declaration": true, 6 | "declarationMap": true, 7 | "esModuleInterop": true, 8 | "incremental": false, 9 | "isolatedModules": true, 10 | "lib": ["es2022", "DOM", "DOM.Iterable"], 11 | "module": "NodeNext", 12 | "moduleDetection": "force", 13 | "moduleResolution": "NodeNext", 14 | "noUncheckedIndexedAccess": true, 15 | "resolveJsonModule": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "target": "ES2022" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/typescript-config/nextjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Next.js", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "plugins": [{ "name": "next" }], 7 | "module": "ESNext", 8 | "moduleResolution": "Bundler", 9 | "allowJs": true, 10 | "jsx": "preserve", 11 | "noEmit": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/typescript-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@workspace/typescript-config", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "PROPRIETARY", 6 | "publishConfig": { 7 | "access": "public" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/typescript-config/react-library.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "React Library", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "jsx": "react-jsx", 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/ui/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "src/styles/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true 11 | }, 12 | "iconLibrary": "lucide", 13 | "aliases": { 14 | "components": "@workspace/ui/components", 15 | "utils": "@workspace/ui/lib/utils", 16 | "hooks": "@workspace/ui/hooks", 17 | "lib": "@workspace/ui/lib", 18 | "ui": "@workspace/ui/components" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/ui/eslint.config.js: -------------------------------------------------------------------------------- 1 | import { config } from "@workspace/eslint-config/react-internal" 2 | 3 | /** @type {import("eslint").Linter.Config} */ 4 | export default config 5 | -------------------------------------------------------------------------------- /packages/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@workspace/ui", 3 | "version": "0.0.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "lint": "eslint . --max-warnings 0" 8 | }, 9 | "dependencies": { 10 | "@radix-ui/react-slot": "^1.1.2", 11 | "@radix-ui/react-switch": "^1.1.3", 12 | "class-variance-authority": "^0.7.0", 13 | "clsx": "^2.1.1", 14 | "framer-motion": "^12.4.3", 15 | "fumadocs-ui": "14.6.0", 16 | "lucide-react": "0.456.0", 17 | "mini-svg-data-uri": "^1.4.4", 18 | "next-themes": "^0.4.3", 19 | "react": "^19.0.0", 20 | "react-dom": "^19.0.0", 21 | "tailwind-merge": "^2.5.4", 22 | "tailwindcss-animate": "^1.0.7", 23 | "zod": "^3.23.8" 24 | }, 25 | "devDependencies": { 26 | "@turbo/gen": "^2.2.3", 27 | "@types/node": "^22.9.0", 28 | "@types/react": "^19.0.1", 29 | "@types/react-dom": "^19.0.2", 30 | "@workspace/eslint-config": "workspace:*", 31 | "@workspace/typescript-config": "workspace:*", 32 | "autoprefixer": "^10.4.20", 33 | "postcss": "^8.4.47", 34 | "tailwindcss": "^3.4.14", 35 | "typescript": "^5.6.3", 36 | "eslint": "^9.19.0" 37 | }, 38 | "exports": { 39 | "./globals.css": "./src/styles/globals.css", 40 | "./postcss.config": "./postcss.config.mjs", 41 | "./tailwind.config": "./tailwind.config.ts", 42 | "./lib/*": "./src/lib/*.ts", 43 | "./components/*": "./src/components/*.tsx", 44 | "./hooks/*": "./src/hooks/*.ts" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/ui/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | autoprefixer: {}, 6 | }, 7 | }; 8 | 9 | export default config; 10 | -------------------------------------------------------------------------------- /packages/ui/src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /packages/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@workspace/typescript-config/react-library.json", 3 | "compilerOptions": { 4 | //"outDir": "dist" 5 | "baseUrl": ".", 6 | "paths": { 7 | "@workspace/ui/*": ["./src/*"] 8 | } 9 | }, 10 | "include": ["."], 11 | "exclude": ["node_modules", "dist"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/ui/tsconfig.lint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@workspace/typescript-config/react-library.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src", "turbo"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/vue/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @bprogress/vue 2 | 3 | ## 1.1.5 4 | 5 | ### Patch Changes 6 | 7 | - chore: change repo link 8 | - chore: upgrade to `@bprogress/core@1.3.4` 9 | 10 | ## 1.1.4 11 | 12 | ### Patch Changes 13 | 14 | - feat: add auto stop control 15 | - chore: upgrade to `@bprogress/core@1.3.3` 16 | 17 | ## 1.1.3 18 | 19 | ### Patch Changes 20 | 21 | - chore: upgrade to `@bprogress/core@1.3.2` 22 | 23 | ## 1.1.2 24 | 25 | ### Patch Changes 26 | 27 | - fix: prevent progress when the link has a `download` attribute 28 | 29 | ## 1.1.1 30 | 31 | ### Patch Changes 32 | 33 | - chore: upgrade to `@bprogress/core@1.3.1` 34 | 35 | ## 1.1.0 36 | 37 | ### Minor Changes 38 | 39 | - feat: add `dec` method to `ProgressProvider` 40 | - feat: add `Indeterminate` component 41 | - chore: upgrade to `@bprogress/core@1.3.0` 42 | 43 | ## 1.0.1 44 | 45 | ### Patch Changes 46 | 47 | - chore: improve `package.json` description 48 | 49 | ## 1.0.0 50 | 51 | ### Major Changes 52 | 53 | - feat: create `@bprogress/vue` package 54 | -------------------------------------------------------------------------------- /packages/vue/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Elliot Sutton 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/vue/README.md: -------------------------------------------------------------------------------- 1 | # BProgress for Vue 2 | 3 | Create your own **progress bar** with **Vue** 4 | 5 | ## Import 6 | 7 | ```tsx 8 | import { ProgressProvider } from '@bprogress/vue'; 9 | ``` 10 | 11 | The `@bprogress/vue` package is a **utility** that lets you easily manage a progress bar, while remaining flexible with regard to the router you're using. **It doesn't automatically start the progress bar when browsing**, so you'll have to manage this logic yourself, unless you're using one of the integrations below. 12 | 13 | ### Vue Frameworks Integrations 14 | 15 | - Soon... 16 | 17 | ## Usage 18 | 19 | ```vue 20 | ... 21 | ``` 22 | 23 | ## Example 24 | 25 | ```vue title="src/Root.vue" 26 | 30 | 31 | 36 | ``` 37 | 38 | ```ts title="src/main.ts" 39 | import { createApp } from 'vue'; 40 | import Root from './Root.vue'; 41 | 42 | createApp(Root).mount('#app'); 43 | ``` 44 | 45 | ```vue title="src/App.vue" 46 | 51 | 52 | 58 | ``` 59 | 60 | ## More information on documentation 61 | 62 | Go to the [documentation](https://bprogress.vercel.app/docs/vue/installation) to learn more about BProgress. 63 | 64 | ## Issues 65 | 66 | If you encounter any problems, do not hesitate to [open an issue](https://github.com/imskyleen/bprogress/issues) or make a PR [here](https://github.com/imskyleen/bprogress). 67 | 68 | ## LICENSE 69 | 70 | MIT 71 | -------------------------------------------------------------------------------- /packages/vue/__tests__/utils/classnames.test.ts: -------------------------------------------------------------------------------- 1 | import { classNames } from '../../src/utils/classnames'; 2 | 3 | describe('classNames', () => { 4 | it("renvoie une chaîne vide lorsqu'aucun argument n'est fourni", () => { 5 | expect(classNames()).toBe(''); 6 | }); 7 | 8 | it("renvoie le nom de classe unique lorsqu'un seul argument est fourni", () => { 9 | expect(classNames('foo')).toBe('foo'); 10 | }); 11 | 12 | it('concatène plusieurs noms de classe avec un espace', () => { 13 | expect(classNames('foo', 'bar', 'baz')).toBe('foo bar baz'); 14 | }); 15 | 16 | it('ignore les valeurs falsy (undefined, null, false)', () => { 17 | expect(classNames('foo', undefined, null, false, 'bar')).toBe('foo bar'); 18 | }); 19 | 20 | it('ignore les chaînes vides et concatène le reste avec des espaces', () => { 21 | expect(classNames('foo', '', 'bar')).toBe('foo bar'); 22 | }); 23 | 24 | it('fonctionne avec une combinaison de valeurs valides et invalides', () => { 25 | expect(classNames('', 'foo', null, 'bar', undefined, false, 'baz')).toBe( 26 | 'foo bar baz', 27 | ); 28 | }); 29 | 30 | it('gère les tableaux de noms de classe', () => { 31 | expect(classNames(['foo', 'bar'])).toBe('foo bar'); 32 | expect(classNames('foo', ['bar', 'baz'])).toBe('foo bar baz'); 33 | }); 34 | 35 | it('gère les objets avec des valeurs booléennes', () => { 36 | expect(classNames({ foo: true, bar: false, baz: true })).toBe('foo baz'); 37 | }); 38 | 39 | it('gère une combinaison de chaînes, tableaux et objets', () => { 40 | expect( 41 | classNames('foo', ['bar', 'baz'], { qux: true, quux: false }, undefined, [ 42 | 'corge', 43 | { grault: true, garply: false }, 44 | ]), 45 | ).toBe('foo bar baz qux corge grault'); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /packages/vue/eslint.config.js: -------------------------------------------------------------------------------- 1 | import { config } from '@workspace/eslint-config/vue'; 2 | 3 | /** @type {import("eslint").Linter.Config} */ 4 | export default [ 5 | ...config, 6 | { 7 | files: ['**/__tests__/**/*.{ts,js,vue}'], 8 | rules: { 9 | '@typescript-eslint/no-explicit-any': 'off', 10 | 'vue/one-component-per-file': 'off', 11 | 'vue/order-in-components': 'off', 12 | }, 13 | }, 14 | ]; 15 | -------------------------------------------------------------------------------- /packages/vue/jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { JestConfigWithTsJest } from 'ts-jest'; 2 | 3 | const config: JestConfigWithTsJest = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'jsdom', 6 | transform: { 7 | '^.+\\.(ts)$': 'ts-jest', 8 | '.*\\.(vue)$': './vue3JestHack.js', 9 | }, 10 | moduleFileExtensions: ['vue', 'ts', 'js', 'json'], 11 | moduleNameMapper: { 12 | '^@/(.*)$': '/src/$1', 13 | '\\.(css)$': '/test/mocks/emptyMock.js', 14 | '^@vue/test-utils': 15 | '/node_modules/@vue/test-utils/dist/vue-test-utils.cjs.js', 16 | }, 17 | modulePathIgnorePatterns: ['node_modules'], 18 | testEnvironmentOptions: { 19 | customExportConditions: ['node', 'node-addons'], 20 | }, 21 | setupFilesAfterEnv: ['/jest.setup.ts'], 22 | silent: true, 23 | }; 24 | 25 | export default config; 26 | -------------------------------------------------------------------------------- /packages/vue/jest.setup.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | -------------------------------------------------------------------------------- /packages/vue/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import Vue from 'vue'; 3 | export default Vue; 4 | } 5 | -------------------------------------------------------------------------------- /packages/vue/src/components/bar.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 19 | -------------------------------------------------------------------------------- /packages/vue/src/components/indeterminate.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 20 | -------------------------------------------------------------------------------- /packages/vue/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Progress } from './progress.vue'; 2 | export { default as Bar } from './bar.vue'; 3 | export { default as Peg } from './peg.vue'; 4 | export { default as Spinner } from './spinner.vue'; 5 | export { default as SpinnerIcon } from './spinner-icon.vue'; 6 | export { default as Indeterminate } from './indeterminate.vue'; 7 | -------------------------------------------------------------------------------- /packages/vue/src/components/peg.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 19 | -------------------------------------------------------------------------------- /packages/vue/src/components/progress.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 46 | -------------------------------------------------------------------------------- /packages/vue/src/components/spinner-icon.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 19 | -------------------------------------------------------------------------------- /packages/vue/src/components/spinner.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 19 | -------------------------------------------------------------------------------- /packages/vue/src/composables/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-progress'; 2 | export * from './use-anchor-progress'; 3 | -------------------------------------------------------------------------------- /packages/vue/src/composables/use-progress.ts: -------------------------------------------------------------------------------- 1 | import { inject } from 'vue'; 2 | import type { ProgressContextValue } from '../types'; 3 | 4 | const progressSymbol = Symbol('ProgressContext'); 5 | 6 | export function useProgress(): ProgressContextValue { 7 | const context = inject(progressSymbol); 8 | if (!context) { 9 | throw new Error('useProgress must be used within a ProgressProvider'); 10 | } 11 | return context; 12 | } 13 | 14 | export { progressSymbol }; 15 | -------------------------------------------------------------------------------- /packages/vue/src/index.ts: -------------------------------------------------------------------------------- 1 | export { default as ProgressProvider } from './providers/progress-provider.vue'; 2 | export * from './composables'; 3 | export * from './components'; 4 | export type * from './types'; 5 | -------------------------------------------------------------------------------- /packages/vue/src/utils/classnames.ts: -------------------------------------------------------------------------------- 1 | import { ClassValue } from '../types'; 2 | 3 | export function classNames( 4 | ...classes: (ClassValue | undefined | null | false)[] 5 | ): string { 6 | const result: string[] = []; 7 | 8 | const process = (input: ClassValue | undefined | null | false): void => { 9 | if (!input) return; 10 | if (typeof input === 'string') { 11 | if (input.trim()) result.push(input); 12 | } else if (Array.isArray(input)) { 13 | input.forEach((item) => process(item)); 14 | } else if (typeof input === 'object') { 15 | for (const key in input) { 16 | if (Object.prototype.hasOwnProperty.call(input, key) && input[key]) { 17 | result.push(key); 18 | } 19 | } 20 | } 21 | }; 22 | 23 | classes.forEach((item) => process(item)); 24 | return result.join(' '); 25 | } 26 | -------------------------------------------------------------------------------- /packages/vue/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": ["node", "jest", "@testing-library/jest-dom"], 4 | "target": "ESNext", 5 | "module": "ESNext", 6 | "moduleResolution": "node", 7 | "strict": true, 8 | "jsx": "preserve", 9 | "importHelpers": true, 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "skipLibCheck": true, 13 | "forceConsistentCasingInFileNames": true, 14 | "declaration": true, 15 | "declarationDir": "dist/types", 16 | "sourceMap": true, 17 | "baseUrl": ".", 18 | "paths": { 19 | "@/*": ["src/*"] 20 | }, 21 | }, 22 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "__tests__", "shims-vue.d.ts"], 23 | "exclude": ["node_modules", "dist"] 24 | } 25 | -------------------------------------------------------------------------------- /packages/vue/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import vue from '@vitejs/plugin-vue'; 3 | import dts from 'vite-plugin-dts'; 4 | import path from 'path'; 5 | 6 | export default defineConfig({ 7 | plugins: [ 8 | vue(), 9 | dts({ 10 | insertTypesEntry: true, 11 | exclude: ['**/__tests__/**/*', '**/*.test.*'], 12 | }), 13 | ], 14 | build: { 15 | lib: { 16 | entry: path.resolve(__dirname, 'src/index.ts'), 17 | name: 'BProgressVue', 18 | fileName: (format) => `index.${format}.js`, 19 | }, 20 | rollupOptions: { 21 | external: ['vue', '@bprogress/core'], 22 | output: { 23 | globals: { 24 | vue: 'Vue', 25 | '@bprogress/core': 'BProgressCore', 26 | }, 27 | }, 28 | }, 29 | }, 30 | }); 31 | -------------------------------------------------------------------------------- /packages/vue/vue3JestHack.js: -------------------------------------------------------------------------------- 1 | import { registerTS } from '@vue/compiler-sfc'; 2 | import * as ts from 'typescript'; 3 | 4 | registerTS(() => ts); 5 | 6 | import vueJest from '@vue/vue3-jest'; 7 | export default vueJest; 8 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "apps/*" 3 | - "packages/*" 4 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@workspace/typescript-config/base.json" 3 | } 4 | 5 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "ui": "tui", 4 | "tasks": { 5 | "build": { 6 | "dependsOn": ["^build"], 7 | "inputs": ["$TURBO_DEFAULT$", ".env*"], 8 | "outputs": [".next/**", "dist/**", "!.next/cache/**"] 9 | }, 10 | "lint": { 11 | "dependsOn": ["^lint"] 12 | }, 13 | "test": { 14 | "dependsOn": ["^test"] 15 | }, 16 | "check-types": { 17 | "dependsOn": ["^check-types"] 18 | }, 19 | "dev": { 20 | "cache": false, 21 | "persistent": true 22 | } 23 | } 24 | } 25 | --------------------------------------------------------------------------------