@vctqs1/nav-progress-bar 0.0.2-4 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,6 +4,25 @@ A zero-dependency, CSP-safe top-of-page progress bar built as a native Web Compo
4
4
 
5
5
  > Originally built to solve the [Next.js App Router `loading.js` dead gap](https://github.com/vercel/next.js/issues/43548), but the underlying mechanism (the browser [Navigation API](https://developer.mozilla.org/en-US/docs/Web/API/Navigation_API)) works anywhere.
6
6
 
7
+ ## Table of Contents
8
+
9
+ - [Features](#features)
10
+ - [Installation](#installation)
11
+ - [Quick Start](#quick-start)
12
+ - [Next.js App Router](#nextjs-app-router)
13
+ - [Nuxt](#nuxt)
14
+ - [SvelteKit](#sveltekit)
15
+ - [Astro](#astro)
16
+ - [Manual start (non-Next.js)](#manual-start-non-nextjs)
17
+ - [Vanilla HTML](#vanilla-html-snippet)
18
+ - [ES Module](#es-module)
19
+ - [Color Configuration](#color-configuration)
20
+ - [API](#api)
21
+ - [How It Works](#how-it-works)
22
+ - [Browser Support](#browser-support)
23
+ - [Debugging](#debugging)
24
+ - [License](#license)
25
+
7
26
  ## Features
8
27
 
9
28
  - **Zero dependencies** — pure Web Component, no React, no Vue, nothing
@@ -25,31 +44,7 @@ yarn add @vctqs1/nav-progress-bar
25
44
 
26
45
  ## Quick Start
27
46
 
28
- ### Vanilla HTML
29
-
30
- ```html
31
- <script type="module">
32
- import { registerNavProgressBar } from '@vctqs1/nav-progress-bar';
33
- registerNavProgressBar();
34
- </script>
35
-
36
- <vctqs1-nav-progress-bar></vctqs1-nav-progress-bar>
37
- ```
38
-
39
- ### ES Module
40
-
41
- ```ts
42
- import { registerNavProgressBar, getNavProgressBar } from '@vctqs1/nav-progress-bar';
43
-
44
- registerNavProgressBar();
45
-
46
- // The bar auto-starts on navigate and auto-finishes on navigatesuccess.
47
- // You can also control it manually:
48
- getNavProgressBar()?.start();
49
- getNavProgressBar()?.finish();
50
- ```
51
-
52
- ## Framework Guides
47
+ Pick your framework below. For most SPA routers the Navigation API fires automatically after `registerNavProgressBar()` — no extra wiring needed. If you need to force a manual start signal, see [Manual start (non-Next.js)](#manual-start-non-nextjs) below.
53
48
 
54
49
  ### Next.js App Router
55
50
 
@@ -116,6 +111,11 @@ User clicks <Link>
116
111
  → "navigatesuccess" fires → bar finishes
117
112
  ```
118
113
 
114
+ > 🎬 **Demo** — [watch the bar in action with Next.js App Router →](https://github.com/vctqs1/nav-progress-bar#nextjs-app-router)
115
+
116
+
117
+ <video src="https://github.com/user-attachments/assets/4144ed95-8c25-4aa9-b804-905ac24805b4" controls width="100%"></video>
118
+
119
119
  ---
120
120
 
121
121
  ### Nuxt
@@ -181,7 +181,51 @@ registerNavProgressBar();
181
181
 
182
182
  ---
183
183
 
184
- ### Vanilla HTML
184
+ ### Manual start (non-Next.js)
185
+
186
+ Most SPA routers trigger browser navigation events automatically, so the bar starts/finishes on its own after `registerNavProgressBar()`.
187
+ If you need to force an immediate start signal, add a guarded listener:
188
+
189
+ ```ts
190
+ import { registerNavProgressBar, getNavProgressBar } from '@vctqs1/nav-progress-bar';
191
+
192
+ registerNavProgressBar();
193
+
194
+ const nav = (globalThis as { navigation?: EventTarget }).navigation;
195
+ if (nav?.addEventListener) {
196
+ nav.addEventListener('navigate', () => getNavProgressBar()?.start());
197
+ }
198
+ ```
199
+
200
+ ---
201
+
202
+ ### Vanilla HTML (snippet)
203
+
204
+ ```html
205
+ <script type="module">
206
+ import { registerNavProgressBar } from '@vctqs1/nav-progress-bar';
207
+ registerNavProgressBar();
208
+ </script>
209
+
210
+ <vctqs1-nav-progress-bar></vctqs1-nav-progress-bar>
211
+ ```
212
+
213
+ ### ES Module
214
+
215
+ ```ts
216
+ import { registerNavProgressBar, getNavProgressBar } from '@vctqs1/nav-progress-bar';
217
+
218
+ registerNavProgressBar();
219
+
220
+ // The bar auto-starts on navigate and auto-finishes on navigatesuccess.
221
+ // You can also control it manually:
222
+ getNavProgressBar()?.start();
223
+ getNavProgressBar()?.finish();
224
+ ```
225
+
226
+ ---
227
+
228
+ ### Vanilla HTML (full page)
185
229
 
186
230
  ```html
187
231
  <!DOCTYPE html>
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(){let e=globalThis.navigation;if(!(!e||typeof e!=`object`)&&!(!(`addEventListener`in e)||!(`removeEventListener`in e)))return e}var t=class extends HTMLElement{_layoutSheet=void 0;_sheet=void 0;_progressSheet=void 0;_autoTimer=void 0;_startTime=void 0;_options;static get observedAttributes(){return[`primary`]}constructor(e={}){super(),this._options=e}_onNavigateSuccess=()=>this.finish();_onNavigate=()=>this.start();connectedCallback(){this._render();let t=e();t&&(t.addEventListener(`navigate`,this._onNavigate),t.addEventListener(`navigatesuccess`,this._onNavigateSuccess))}disconnectedCallback(){let t=e();t&&(t.removeEventListener(`navigate`,this._onNavigate),t.removeEventListener(`navigatesuccess`,this._onNavigateSuccess)),this._clearTimer()}attributeChangedCallback(){this._sheet&&this._applyColorSheet()}_resolveColor(e,t,n){let r=e??t;return r?r.startsWith(`--`)?`var(${r}, ${n})`:r:n}_buildColorSheet(){let e=this._resolveColor(this.getAttribute(`primary`),this._options.primary,`#006bde`),t=new CSSStyleSheet;return t.insertRule(`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=globalThis.HTMLElement??class{};function t(){let e=globalThis.navigation;if(!(!e||typeof e!=`object`)&&!(!(`addEventListener`in e)||!(`removeEventListener`in e)))return e}var n=class extends e{_layoutSheet=void 0;_sheet=void 0;_progressSheet=void 0;_autoTimer=void 0;_startTime=void 0;_options;static get observedAttributes(){return[`primary`]}constructor(e={}){super(),this._options=e}_onNavigateSuccess=()=>this.finish();_onNavigate=()=>this.start();connectedCallback(){this._render();let e=t();e&&(e.addEventListener(`navigate`,this._onNavigate),e.addEventListener(`navigatesuccess`,this._onNavigateSuccess))}disconnectedCallback(){let e=t();e&&(e.removeEventListener(`navigate`,this._onNavigate),e.removeEventListener(`navigatesuccess`,this._onNavigateSuccess)),this._clearTimer()}attributeChangedCallback(){this._sheet&&this._applyColorSheet()}_resolveColor(e,t,n){let r=e??t;return r?r.startsWith(`--`)?`var(${r}, ${n})`:r:n}_buildColorSheet(){let e=this._resolveColor(this.getAttribute(`primary`),this._options.primary,`#006bde`),t=new CSSStyleSheet;return t.insertRule(`
2
2
  .bar {
3
3
  height: 3px;
4
4
  background: ${e};
@@ -20,4 +20,4 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(){
20
20
  z-index: 9999;
21
21
  pointer-events: none;
22
22
  }
23
- `),this._layoutSheet=t;let n=new CSSStyleSheet;if(n.insertRule(`.bar { width: 0%; }`),this._progressSheet=n,this._sheet=this._buildColorSheet(),e.adoptedStyleSheets=[this._layoutSheet,this._sheet,this._progressSheet],!e.querySelector(`.bar`)){let t=document.createElement(`div`);t.className=`bar`,e.append(t)}}_setWidth(e){this._progressSheet&&this._progressSheet.replaceSync(`.bar { width: ${e}%; }`)}start(){this._clearTimer(),this._setWidth(0),this._applyActive(!0);let e=0;return this._autoTimer=setInterval(()=>{e+=(85-e)*.08,this._setWidth(Math.min(e,85))},200),this}finish(){this._clearTimer();let e=this.shadowRoot?.querySelector(`.bar`);return e?(e.classList.remove(`active`),e.classList.add(`complete`),this._setWidth(100),setTimeout(()=>{e.classList.remove(`complete`),this._setWidth(0),this._applyActive(!1)},700),this):this}_applyActive(e){let t=this.shadowRoot?.querySelector(`.bar`);if(t&&(t.classList.toggle(`active`,e),e&&this._startTime===void 0&&(this._startTime=performance.now()),!e&&this._startTime!==void 0)){let e=performance.now()-this._startTime;console.log(`[top-loading-bar] navigation took ${e.toFixed(0)}ms`),this._startTime=void 0}}_clearTimer(){this._autoTimer!==void 0&&(clearInterval(this._autoTimer),this._autoTimer=void 0)}},n=`vctqs1-nav-progress-bar`;function r(r){if(!(typeof customElements>`u`)&&e()&&!customElements.get(`vctqs1-nav-progress-bar`)){class e extends t{constructor(){super(r)}}customElements.define(n,e)}}function i(){return document.querySelector(n)}exports.NavProgressBar=t,exports.TAG_NAME=n,exports.getNavProgressBar=i,exports.registerNavProgressBar=r;
23
+ `),this._layoutSheet=t;let n=new CSSStyleSheet;if(n.insertRule(`.bar { width: 0%; }`),this._progressSheet=n,this._sheet=this._buildColorSheet(),e.adoptedStyleSheets=[this._layoutSheet,this._sheet,this._progressSheet],!e.querySelector(`.bar`)){let t=document.createElement(`div`);t.className=`bar`,e.append(t)}}_setWidth(e){this._progressSheet&&this._progressSheet.replaceSync(`.bar { width: ${e}%; }`)}start(){this._clearTimer(),this._setWidth(0),this._applyActive(!0);let e=0;return this._autoTimer=setInterval(()=>{e+=(85-e)*.08,this._setWidth(Math.min(e,85))},200),this}finish(){this._clearTimer();let e=this.shadowRoot?.querySelector(`.bar`);return e?(e.classList.remove(`active`),e.classList.add(`complete`),this._setWidth(100),setTimeout(()=>{e.classList.remove(`complete`),this._setWidth(0),this._applyActive(!1)},700),this):this}_applyActive(e){let t=this.shadowRoot?.querySelector(`.bar`);if(t&&(t.classList.toggle(`active`,e),e&&this._startTime===void 0&&(this._startTime=performance.now()),!e&&this._startTime!==void 0)){let e=performance.now()-this._startTime;console.log(`[top-loading-bar] navigation took ${e.toFixed(0)}ms`),this._startTime=void 0}}_clearTimer(){this._autoTimer!==void 0&&(clearInterval(this._autoTimer),this._autoTimer=void 0)}},r=`vctqs1-nav-progress-bar`;function i(e){if(!(typeof customElements>`u`)&&t()&&!customElements.get(`vctqs1-nav-progress-bar`)){class t extends n{constructor(){super(e)}}customElements.define(r,t)}}function a(){return document.querySelector(r)}exports.NavProgressBar=n,exports.TAG_NAME=r,exports.getNavProgressBar=a,exports.registerNavProgressBar=i;
package/dist/index.js CHANGED
@@ -1,9 +1,10 @@
1
1
  //#region src/lib/nav-progress-bar.ts
2
- function e() {
2
+ var e = globalThis.HTMLElement ?? class {};
3
+ function t() {
3
4
  let e = globalThis.navigation;
4
5
  if (!(!e || typeof e != "object") && !(!("addEventListener" in e) || !("removeEventListener" in e))) return e;
5
6
  }
6
- var t = class extends HTMLElement {
7
+ var n = class extends e {
7
8
  _layoutSheet = void 0;
8
9
  _sheet = void 0;
9
10
  _progressSheet = void 0;
@@ -20,12 +21,12 @@ var t = class extends HTMLElement {
20
21
  _onNavigate = () => this.start();
21
22
  connectedCallback() {
22
23
  this._render();
23
- let t = e();
24
- t && (t.addEventListener("navigate", this._onNavigate), t.addEventListener("navigatesuccess", this._onNavigateSuccess));
24
+ let e = t();
25
+ e && (e.addEventListener("navigate", this._onNavigate), e.addEventListener("navigatesuccess", this._onNavigateSuccess));
25
26
  }
26
27
  disconnectedCallback() {
27
- let t = e();
28
- t && (t.removeEventListener("navigate", this._onNavigate), t.removeEventListener("navigatesuccess", this._onNavigateSuccess)), this._clearTimer();
28
+ let e = t();
29
+ e && (e.removeEventListener("navigate", this._onNavigate), e.removeEventListener("navigatesuccess", this._onNavigateSuccess)), this._clearTimer();
29
30
  }
30
31
  attributeChangedCallback() {
31
32
  this._sheet && this._applyColorSheet();
@@ -93,19 +94,19 @@ var t = class extends HTMLElement {
93
94
  _clearTimer() {
94
95
  this._autoTimer !== void 0 && (clearInterval(this._autoTimer), this._autoTimer = void 0);
95
96
  }
96
- }, n = "vctqs1-nav-progress-bar";
97
- function r(r) {
98
- if (!(typeof customElements > "u") && e() && !customElements.get("vctqs1-nav-progress-bar")) {
99
- class e extends t {
97
+ }, r = "vctqs1-nav-progress-bar";
98
+ function i(e) {
99
+ if (!(typeof customElements > "u") && t() && !customElements.get("vctqs1-nav-progress-bar")) {
100
+ class t extends n {
100
101
  constructor() {
101
- super(r);
102
+ super(e);
102
103
  }
103
104
  }
104
- customElements.define(n, e);
105
+ customElements.define(r, t);
105
106
  }
106
107
  }
107
- function i() {
108
- return document.querySelector(n);
108
+ function a() {
109
+ return document.querySelector(r);
109
110
  }
110
111
  //#endregion
111
- export { t as NavProgressBar, n as TAG_NAME, i as getNavProgressBar, r as registerNavProgressBar };
112
+ export { n as NavProgressBar, r as TAG_NAME, a as getNavProgressBar, i as registerNavProgressBar };
@@ -5,6 +5,7 @@ export interface NavProgressBarOptions {
5
5
  /** Primary color of the progress bar (hex, rgb, or CSS custom property) */
6
6
  primary?: string;
7
7
  }
8
+ declare const HTMLElementBase: typeof HTMLElement;
8
9
  /**
9
10
  * A web component that displays a progress bar during navigation.
10
11
  * Integrates with the Navigation API to automatically start/finish the progress bar.
@@ -35,7 +36,7 @@ export interface NavProgressBarOptions {
35
36
  * <nav-progress-bar primary="#006bde"></nav-progress-bar>
36
37
  * ```
37
38
  */
38
- export declare class NavProgressBar extends HTMLElement {
39
+ export declare class NavProgressBar extends HTMLElementBase {
39
40
  private _layoutSheet;
40
41
  private _sheet;
41
42
  private _progressSheet;
@@ -112,4 +113,5 @@ export declare function registerNavProgressBar(options?: NavProgressBarOptions):
112
113
  * ```
113
114
  */
114
115
  export declare function getNavProgressBar(): NavProgressBar | null;
116
+ export {};
115
117
  //# sourceMappingURL=nav-progress-bar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"nav-progress-bar.d.ts","sourceRoot":"","sources":["../../src/lib/nav-progress-bar.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAmBD;;;;;;;;;;;;;;GAcG;AACH;;;;;;;;;;;;;;GAcG;AACH,qBAAa,cAAe,SAAQ,WAAW;IAC7C,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,MAAM,CAAwC;IACtD,OAAO,CAAC,cAAc,CAAwC;IAC9D,OAAO,CAAC,UAAU,CAAyD;IAC3E,OAAO,CAAC,UAAU,CAAiC;IACnD,OAAO,CAAC,QAAQ,CAAwB;IAExC,MAAM,KAAK,kBAAkB,aAE5B;IAED;;;OAGG;IACH;;;OAGG;gBACS,OAAO,GAAE,qBAA0B;IAK/C,OAAO,CAAC,kBAAkB,CAAuB;IACjD,OAAO,CAAC,WAAW,CAAsB;IAEzC,iBAAiB;IAajB,oBAAoB;IAYpB,wBAAwB;IAMxB,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,gBAAgB;IA2BxB,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,OAAO;IAwCf,OAAO,CAAC,SAAS;IAMjB;;;;OAIG;IACH;;;;OAIG;IACH,KAAK,IAAI,IAAI;IAgBb;;;OAGG;IACH;;;OAGG;IACH,MAAM,IAAI,IAAI;IAmBd,OAAO,CAAC,YAAY;IAqBpB,OAAO,CAAC,WAAW;CAMpB;AAED,8DAA8D;AAC9D,eAAO,MAAM,QAAQ,EAAG,yBAAkC,CAAC;AAE3D;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE,qBAAqB,QAgBrE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,IAAI,CAEzD"}
1
+ {"version":3,"file":"nav-progress-bar.d.ts","sourceRoot":"","sources":["../../src/lib/nav-progress-bar.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAOD,QAAA,MAAM,eAAe,EAAE,OAAO,WAEe,CAAC;AAc9C;;;;;;;;;;;;;;GAcG;AACH;;;;;;;;;;;;;;GAcG;AACH,qBAAa,cAAe,SAAQ,eAAe;IACjD,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,MAAM,CAAwC;IACtD,OAAO,CAAC,cAAc,CAAwC;IAC9D,OAAO,CAAC,UAAU,CAAyD;IAC3E,OAAO,CAAC,UAAU,CAAiC;IACnD,OAAO,CAAC,QAAQ,CAAwB;IAExC,MAAM,KAAK,kBAAkB,aAE5B;IAED;;;OAGG;IACH;;;OAGG;gBACS,OAAO,GAAE,qBAA0B;IAK/C,OAAO,CAAC,kBAAkB,CAAuB;IACjD,OAAO,CAAC,WAAW,CAAsB;IAEzC,iBAAiB;IAajB,oBAAoB;IAYpB,wBAAwB;IAMxB,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,gBAAgB;IA2BxB,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,OAAO;IAwCf,OAAO,CAAC,SAAS;IAMjB;;;;OAIG;IACH;;;;OAIG;IACH,KAAK,IAAI,IAAI;IAgBb;;;OAGG;IACH;;;OAGG;IACH,MAAM,IAAI,IAAI;IAmBd,OAAO,CAAC,YAAY;IAqBpB,OAAO,CAAC,WAAW;CAMpB;AAED,8DAA8D;AAC9D,eAAO,MAAM,QAAQ,EAAG,yBAAkC,CAAC;AAE3D;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE,qBAAqB,QAgBrE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,IAAI,CAEzD"}
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@vctqs1/nav-progress-bar",
3
- "version": "0.0.2-4",
3
+ "version": "0.1.0",
4
+ "repository": "https://github.com/vctqs1/nav-progress-bar",
4
5
  "type": "module",
5
6
  "main": "./dist/index.js",
6
7
  "module": "./dist/index.js",
@@ -19,6 +20,7 @@
19
20
  ],
20
21
  "license": "MIT",
21
22
  "keywords": [
23
+ "toploader",
22
24
  "progress-bar",
23
25
  "navigation",
24
26
  "web-component",