ng-hub-ui-loading 22.1.0 → 22.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
[Español](./README.es.md) | **English**
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/ng-hub-ui-loading)
|
|
6
|
-
[](https://angular.dev)
|
|
7
7
|
[](LICENSE)
|
|
8
8
|
|
|
9
|
-
Standalone loading block for Angular
|
|
9
|
+
Standalone loading block for Angular 21+ — an inline indicator, an overlay pinned over the container that is busy, or a fullscreen curtain, from a single `<hub-loading>` element. Five pure-CSS indicators, an optional logo or image instead of them, an optional message, and a counter-based `HubLoadingService` for the app-wide fullscreen case. Alongside it, `<hub-loading-bar>` — the thin page-progress strip that sits under the navbar, wired to the router and to `HttpClient`. Zero external dependencies; every colour and dimension is a `--hub-loading-*` CSS custom property.
|
|
10
10
|
|
|
11
11
|
## Documentation and Live Examples
|
|
12
12
|
|
|
@@ -492,7 +492,7 @@ Injectable (`providedIn: 'root'`). Drives a single fullscreen overlay attached t
|
|
|
492
492
|
| `hide` | `() => void` | Decrements the counter; destroys the overlay when it reaches zero. |
|
|
493
493
|
| `hideAll` | `() => void` | Forces the counter to zero and destroys the overlay. |
|
|
494
494
|
| `update` | `(options: HubLoadingOptions) => void` | Applies new options to the visible overlay. |
|
|
495
|
-
| `isLoading` | `Signal<boolean>` |
|
|
495
|
+
| `isLoading` | `Signal<boolean>` | `true` while at least one caller still holds a reference — the counter, not the mount. During server rendering it is truthful even though no overlay is mounted. |
|
|
496
496
|
|
|
497
497
|
### `provideHubLoading(config?)`
|
|
498
498
|
|
|
@@ -724,6 +724,27 @@ The internal structure is stable and addressable, for the cases a token cannot r
|
|
|
724
724
|
| `.hub-loading__image` | The `image` asset, plus `--spin` / `--pulse` when animated. |
|
|
725
725
|
| `.hub-loading__message` | The message text. |
|
|
726
726
|
|
|
727
|
+
The bar has its own set, and it is worth knowing because most of it is state you can style
|
|
728
|
+
against rather than structure you have to reach into:
|
|
729
|
+
|
|
730
|
+
| Class | Element |
|
|
731
|
+
| --- | --- |
|
|
732
|
+
| `.hub-loading-bar` | Host block. |
|
|
733
|
+
| `.hub-loading-bar--inline` · `--overlay` · `--fixed` | Mode modifiers. |
|
|
734
|
+
| `.hub-loading-bar--top` · `--bottom` | Placement modifiers; emitted only by the two positioned modes, so they can never reach an inline bar. |
|
|
735
|
+
| `.hub-loading-bar--visible` | Present only while the bar is painted. The fill transition is scoped to it, so a rewind between cycles never animates backwards. |
|
|
736
|
+
| `.hub-loading-bar--indeterminate` | The sweep is running instead of a fill. |
|
|
737
|
+
| `.hub-loading-bar--glow` | The leading-edge glow is on — the shipped default, unless `[glow]="false"` or a re-based `provideHubLoadingBar()` turns it off. |
|
|
738
|
+
| `.hub-loading-bar__indicator` | The fill itself; its `::after` paints the glow. |
|
|
739
|
+
|
|
740
|
+
### Right-to-left
|
|
741
|
+
|
|
742
|
+
Under `[dir='rtl']` the `indeterminate` sweep reverses, so it travels with the text instead
|
|
743
|
+
of against it. Nothing to switch on: the stylesheet reads the direction from the bar itself
|
|
744
|
+
or from any ancestor carrying the attribute, which is where an RTL application already sets
|
|
745
|
+
it. The determinate fill needs no such rule — it is laid out with logical properties and
|
|
746
|
+
mirrors on its own.
|
|
747
|
+
|
|
727
748
|
## ♿ Accessibility
|
|
728
749
|
|
|
729
750
|
- The block is a **status region**: `role="status"`, `aria-live="polite"` and
|
|
@@ -778,7 +799,8 @@ The internal structure is stable and addressable, for the cases a token cannot r
|
|
|
778
799
|
"@angular/common": ">=21.0.0",
|
|
779
800
|
"@angular/core": ">=21.0.0",
|
|
780
801
|
"@angular/router": ">=21.0.0",
|
|
781
|
-
"ng-hub-ui-utils": ">=22.8.0"
|
|
802
|
+
"ng-hub-ui-utils": ">=22.8.0",
|
|
803
|
+
"rxjs": ">=7.5.0"
|
|
782
804
|
}
|
|
783
805
|
```
|
|
784
806
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, makeEnvironmentProviders, inject, input, booleanAttribute, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, ApplicationRef, PLATFORM_ID, signal, createComponent, Injectable, NgZone, DestroyRef, provideAppInitializer } from '@angular/core';
|
|
2
|
+
import { InjectionToken, makeEnvironmentProviders, inject, input, booleanAttribute, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, ApplicationRef, PLATFORM_ID, signal, untracked, createComponent, Injectable, NgZone, DestroyRef, provideAppInitializer } from '@angular/core';
|
|
3
3
|
import { resolveHubAccent } from 'ng-hub-ui-utils';
|
|
4
4
|
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
|
|
5
5
|
import { HttpContextToken, HttpContext } from '@angular/common/http';
|
|
@@ -172,7 +172,16 @@ class HubLoadingService {
|
|
|
172
172
|
document = inject(DOCUMENT);
|
|
173
173
|
platformId = inject(PLATFORM_ID);
|
|
174
174
|
config = inject(HUB_LOADING_CONFIG);
|
|
175
|
-
/**
|
|
175
|
+
/**
|
|
176
|
+
* Number of callers currently requesting the overlay.
|
|
177
|
+
*
|
|
178
|
+
* Read through `untracked` wherever it steers this service's own logic. A caller is not
|
|
179
|
+
* necessarily outside a reactive context — `hide()` from inside an `effect()` is ordinary
|
|
180
|
+
* code — and a tracked read there subscribes that effect to the counter, so anyone else's
|
|
181
|
+
* `show()` re-runs it and retires a reference it never registered, taking the overlay down
|
|
182
|
+
* while other callers are still waiting. Only `isLoading` reads it tracked, and that one is
|
|
183
|
+
* meant to: it exists to be watched.
|
|
184
|
+
*/
|
|
176
185
|
pending = signal(0, /* @ts-ignore */
|
|
177
186
|
...(ngDevMode ? [{ debugName: "pending" }] : /* istanbul ignore next */ []));
|
|
178
187
|
/** Live reference to the mounted overlay; `null` whenever nothing is showing. */
|
|
@@ -204,7 +213,7 @@ class HubLoadingService {
|
|
|
204
213
|
*/
|
|
205
214
|
hide() {
|
|
206
215
|
this.pending.update((count) => Math.max(0, count - 1));
|
|
207
|
-
if (this.pending
|
|
216
|
+
if (untracked(this.pending) === 0) {
|
|
208
217
|
this.unmount();
|
|
209
218
|
}
|
|
210
219
|
}
|
|
@@ -422,6 +431,16 @@ class HubLoadingBarService {
|
|
|
422
431
|
zone = inject(NgZone);
|
|
423
432
|
platformId = inject(PLATFORM_ID);
|
|
424
433
|
/** Number of callers currently waiting on something. */
|
|
434
|
+
/**
|
|
435
|
+
* How many callers are holding the bar up.
|
|
436
|
+
*
|
|
437
|
+
* Read through `untracked` everywhere it steers this service's own logic. A caller is
|
|
438
|
+
* not necessarily outside a reactive context — Angular does not untrack interceptors,
|
|
439
|
+
* so a request fired from inside an `effect()` runs `start()` inside that effect — and a
|
|
440
|
+
* tracked read there subscribes the caller's effect to this counter. Every later request
|
|
441
|
+
* then re-runs it, which is a request loop with the bar as the feedback path. Only
|
|
442
|
+
* `isActive` reads it tracked, and that one is meant to: it exists to be watched.
|
|
443
|
+
*/
|
|
425
444
|
pending = signal(0, /* @ts-ignore */
|
|
426
445
|
...(ngDevMode ? [{ debugName: "pending" }] : /* istanbul ignore next */ []));
|
|
427
446
|
/** Current fill, 0–100. */
|
|
@@ -458,7 +477,7 @@ class HubLoadingBarService {
|
|
|
458
477
|
* Registers one caller. The first one starts a cycle; the rest simply join the count.
|
|
459
478
|
*/
|
|
460
479
|
start() {
|
|
461
|
-
const wasIdle = this.pending
|
|
480
|
+
const wasIdle = untracked(this.pending) === 0;
|
|
462
481
|
this.pending.update((count) => count + 1);
|
|
463
482
|
if (!wasIdle) {
|
|
464
483
|
return;
|
|
@@ -491,7 +510,7 @@ class HubLoadingBarService {
|
|
|
491
510
|
*/
|
|
492
511
|
complete() {
|
|
493
512
|
this.pending.update((count) => Math.max(0, count - 1));
|
|
494
|
-
if (this.pending
|
|
513
|
+
if (untracked(this.pending) === 0) {
|
|
495
514
|
this.finish();
|
|
496
515
|
}
|
|
497
516
|
}
|
|
@@ -549,7 +568,10 @@ class HubLoadingBarService {
|
|
|
549
568
|
finish() {
|
|
550
569
|
this.clearTimer('reveal');
|
|
551
570
|
this.clearTimer('trickle');
|
|
552
|
-
|
|
571
|
+
// Untracked for the same reason as `pending`: `complete()` and `completeAll()` are
|
|
572
|
+
// public and reachable from an effect, and a tracked read here would wake that effect
|
|
573
|
+
// on every later cycle, completing a bar somebody else had just started.
|
|
574
|
+
if (!untracked(this._visible)) {
|
|
553
575
|
this._progress.set(0);
|
|
554
576
|
return;
|
|
555
577
|
}
|
|
@@ -558,7 +580,7 @@ class HubLoadingBarService {
|
|
|
558
580
|
}
|
|
559
581
|
/** Starts the trickle interval, unless it is disabled, already running or unneeded. */
|
|
560
582
|
startTrickling() {
|
|
561
|
-
if (!this.config.trickle || this.timers.trickle !== null || this.pending
|
|
583
|
+
if (!this.config.trickle || this.timers.trickle !== null || untracked(this.pending) === 0) {
|
|
562
584
|
return;
|
|
563
585
|
}
|
|
564
586
|
if (!isPlatformBrowser(this.platformId)) {
|
|
@@ -570,7 +592,10 @@ class HubLoadingBarService {
|
|
|
570
592
|
}
|
|
571
593
|
/** Adds one step, capped at `max` so the trickle can never claim to be finished. */
|
|
572
594
|
advance(amount) {
|
|
573
|
-
|
|
595
|
+
// Untracked for the same reason as `pending`: `inc()` is public, so this read can happen
|
|
596
|
+
// inside a caller's effect, and each step would then re-run it — a bar that advances
|
|
597
|
+
// itself for as long as the guard allows.
|
|
598
|
+
const current = untracked(this._progress);
|
|
574
599
|
const step = amount ?? this.config.trickleFn(current);
|
|
575
600
|
this._progress.set(Math.min(this.config.max, Math.max(0, current + step)));
|
|
576
601
|
}
|
|
@@ -728,7 +753,7 @@ class HubLoadingBarComponent {
|
|
|
728
753
|
_accent = computed(() => resolveHubAccent(this.color()), /* @ts-ignore */
|
|
729
754
|
...(ngDevMode ? [{ debugName: "_accent" }] : /* istanbul ignore next */ []));
|
|
730
755
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: HubLoadingBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
731
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.8", type: HubLoadingBarComponent, isStandalone: true, selector: "hub-loading-bar", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, progress: { classPropertyName: "progress", publicName: "progress", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, glow: { classPropertyName: "glow", publicName: "glow", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "progressbar", "aria-valuemin": "0", "aria-valuemax": "100" }, properties: { "class": "_modifierClasses()", "class.hub-loading-bar--visible": "_visible()", "attr.aria-label": "ariaLabel()", "attr.aria-valuenow": "_announcedValue()", "attr.aria-hidden": "_visible() ? null : \"true\"", "style.--hub-loading-bar-progress": "_fill()", "style.--hub-loading-bar-accent": "_accent()" }, classAttribute: "hub-loading-bar" }, ngImport: i0, template: "<span class=\"hub-loading-bar__indicator\"></span>\n", styles: [":where(.hub-loading-bar){--hub-loading-bar-accent: var(--hub-sys-color-primary, #0d6efd);--hub-loading-bar-height: 3px;--hub-loading-bar-track-bg: transparent;--hub-loading-bar-radius: 0;--hub-loading-bar-speed: .2s;--hub-loading-bar-fade: .3s;--hub-loading-bar-easing: linear;--hub-loading-bar-glow-color: var(--hub-loading-bar-accent);--hub-loading-bar-glow-blur: 10px;--hub-loading-bar-glow-spread: 1px;--hub-loading-bar-indeterminate-speed: 1.6s;--hub-loading-bar-offset: 0px;--hub-loading-bar-z-index: var(--hub-sys-zindex-sticky, 1020);--hub-loading-bar-progress: 0%;--hub-loading-bar-sweep-direction: 1}[dir=rtl] .hub-loading-bar{--hub-loading-bar-sweep-direction: -1}.hub-loading-bar{display:block;position:relative;overflow:hidden;inline-size:100%;block-size:var(--hub-loading-bar-height);background:var(--hub-loading-bar-track-bg);border-radius:var(--hub-loading-bar-radius);opacity:0;pointer-events:none;transition:opacity var(--hub-loading-bar-fade) ease}.hub-loading-bar--visible{opacity:1}.hub-loading-bar--overlay,.hub-loading-bar--fixed{inset-inline:0;z-index:var(--hub-loading-bar-z-index)}.hub-loading-bar--overlay{position:absolute}.hub-loading-bar--fixed{position:fixed}.hub-loading-bar--top{inset-block-start:var(--hub-loading-bar-offset)}.hub-loading-bar--bottom{inset-block-end:var(--hub-loading-bar-offset)}.hub-loading-bar__indicator{display:block;position:relative;inline-size:var(--hub-loading-bar-progress);block-size:100%;background:var(--hub-loading-bar-accent);border-radius:inherit}.hub-loading-bar--visible .hub-loading-bar__indicator{transition:inline-size var(--hub-loading-bar-speed) var(--hub-loading-bar-easing)}.hub-loading-bar--glow .hub-loading-bar__indicator:after{content:\"\";position:absolute;inset-block:0;inset-inline-end:0;inline-size:var(--hub-loading-bar-height);box-shadow:0 0 var(--hub-loading-bar-glow-blur) var(--hub-loading-bar-glow-spread) var(--hub-loading-bar-glow-color),0 0 calc(var(--hub-loading-bar-glow-blur) / 2) var(--hub-loading-bar-glow-color)}.hub-loading-bar--indeterminate .hub-loading-bar__indicator,.hub-loading-bar--visible.hub-loading-bar--indeterminate .hub-loading-bar__indicator{inline-size:33%;transition:none;animation:hub-loading-bar-sweep var(--hub-loading-bar-indeterminate-speed) ease-in-out infinite}@media(prefers-reduced-motion:reduce){.hub-loading-bar{--hub-loading-bar-indeterminate-speed: 3.2s}}@keyframes hub-loading-bar-sweep{0%{transform:translate(calc(-100% * var(--hub-loading-bar-sweep-direction)))}to{transform:translate(calc(300% * var(--hub-loading-bar-sweep-direction)))}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
756
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.8", type: HubLoadingBarComponent, isStandalone: true, selector: "hub-loading-bar", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, progress: { classPropertyName: "progress", publicName: "progress", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, glow: { classPropertyName: "glow", publicName: "glow", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "progressbar", "aria-valuemin": "0", "aria-valuemax": "100" }, properties: { "class": "_modifierClasses()", "class.hub-loading-bar--visible": "_visible()", "attr.aria-label": "ariaLabel()", "attr.aria-valuenow": "_announcedValue()", "attr.aria-hidden": "_visible() ? null : \"true\"", "style.--hub-loading-bar-progress": "_fill()", "style.--hub-loading-bar-accent": "_accent()" }, classAttribute: "hub-loading-bar" }, ngImport: i0, template: "<span class=\"hub-loading-bar__indicator\"></span>\n", styles: [":where(.hub-loading-bar){--hub-loading-bar-accent: var(--hub-sys-color-primary, #0d6efd);--hub-loading-bar-height: 3px;--hub-loading-bar-track-bg: transparent;--hub-loading-bar-radius: 0;--hub-loading-bar-speed: .2s;--hub-loading-bar-fade: .3s;--hub-loading-bar-easing: linear;--hub-loading-bar-glow-color: var(--hub-loading-bar-accent);--hub-loading-bar-glow-blur: 10px;--hub-loading-bar-glow-spread: 1px;--hub-loading-bar-indeterminate-speed: 1.6s;--hub-loading-bar-offset: 0px;--hub-loading-bar-z-index: var(--hub-sys-zindex-sticky, 1020);--hub-loading-bar-progress: 0%;--hub-loading-bar-sweep-direction: 1}[dir=rtl] .hub-loading-bar,.hub-loading-bar[dir=rtl]{--hub-loading-bar-sweep-direction: -1}.hub-loading-bar{display:block;position:relative;overflow:hidden;inline-size:100%;block-size:var(--hub-loading-bar-height);background:var(--hub-loading-bar-track-bg);border-radius:var(--hub-loading-bar-radius);opacity:0;pointer-events:none;transition:opacity var(--hub-loading-bar-fade) ease}.hub-loading-bar--visible{opacity:1}.hub-loading-bar--overlay,.hub-loading-bar--fixed{inset-inline:0;z-index:var(--hub-loading-bar-z-index)}.hub-loading-bar--overlay{position:absolute}.hub-loading-bar--fixed{position:fixed}.hub-loading-bar--top{inset-block-start:var(--hub-loading-bar-offset)}.hub-loading-bar--bottom{inset-block-end:var(--hub-loading-bar-offset)}.hub-loading-bar__indicator{display:block;position:relative;inline-size:var(--hub-loading-bar-progress);block-size:100%;background:var(--hub-loading-bar-accent);border-radius:inherit}.hub-loading-bar--visible .hub-loading-bar__indicator{transition:inline-size var(--hub-loading-bar-speed) var(--hub-loading-bar-easing)}.hub-loading-bar--glow .hub-loading-bar__indicator:after{content:\"\";position:absolute;inset-block:0;inset-inline-end:0;inline-size:var(--hub-loading-bar-height);box-shadow:0 0 var(--hub-loading-bar-glow-blur) var(--hub-loading-bar-glow-spread) var(--hub-loading-bar-glow-color),0 0 calc(var(--hub-loading-bar-glow-blur) / 2) var(--hub-loading-bar-glow-color)}.hub-loading-bar--indeterminate .hub-loading-bar__indicator,.hub-loading-bar--visible.hub-loading-bar--indeterminate .hub-loading-bar__indicator{inline-size:33%;transition:none;animation:hub-loading-bar-sweep var(--hub-loading-bar-indeterminate-speed) ease-in-out infinite}@media(prefers-reduced-motion:reduce){.hub-loading-bar{--hub-loading-bar-indeterminate-speed: 3.2s}}@keyframes hub-loading-bar-sweep{0%{transform:translate(calc(-100% * var(--hub-loading-bar-sweep-direction)))}to{transform:translate(calc(300% * var(--hub-loading-bar-sweep-direction)))}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
732
757
|
}
|
|
733
758
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: HubLoadingBarComponent, decorators: [{
|
|
734
759
|
type: Component,
|
|
@@ -744,7 +769,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
744
769
|
'[attr.aria-hidden]': '_visible() ? null : "true"',
|
|
745
770
|
'[style.--hub-loading-bar-progress]': '_fill()',
|
|
746
771
|
'[style.--hub-loading-bar-accent]': '_accent()'
|
|
747
|
-
}, template: "<span class=\"hub-loading-bar__indicator\"></span>\n", styles: [":where(.hub-loading-bar){--hub-loading-bar-accent: var(--hub-sys-color-primary, #0d6efd);--hub-loading-bar-height: 3px;--hub-loading-bar-track-bg: transparent;--hub-loading-bar-radius: 0;--hub-loading-bar-speed: .2s;--hub-loading-bar-fade: .3s;--hub-loading-bar-easing: linear;--hub-loading-bar-glow-color: var(--hub-loading-bar-accent);--hub-loading-bar-glow-blur: 10px;--hub-loading-bar-glow-spread: 1px;--hub-loading-bar-indeterminate-speed: 1.6s;--hub-loading-bar-offset: 0px;--hub-loading-bar-z-index: var(--hub-sys-zindex-sticky, 1020);--hub-loading-bar-progress: 0%;--hub-loading-bar-sweep-direction: 1}[dir=rtl] .hub-loading-bar{--hub-loading-bar-sweep-direction: -1}.hub-loading-bar{display:block;position:relative;overflow:hidden;inline-size:100%;block-size:var(--hub-loading-bar-height);background:var(--hub-loading-bar-track-bg);border-radius:var(--hub-loading-bar-radius);opacity:0;pointer-events:none;transition:opacity var(--hub-loading-bar-fade) ease}.hub-loading-bar--visible{opacity:1}.hub-loading-bar--overlay,.hub-loading-bar--fixed{inset-inline:0;z-index:var(--hub-loading-bar-z-index)}.hub-loading-bar--overlay{position:absolute}.hub-loading-bar--fixed{position:fixed}.hub-loading-bar--top{inset-block-start:var(--hub-loading-bar-offset)}.hub-loading-bar--bottom{inset-block-end:var(--hub-loading-bar-offset)}.hub-loading-bar__indicator{display:block;position:relative;inline-size:var(--hub-loading-bar-progress);block-size:100%;background:var(--hub-loading-bar-accent);border-radius:inherit}.hub-loading-bar--visible .hub-loading-bar__indicator{transition:inline-size var(--hub-loading-bar-speed) var(--hub-loading-bar-easing)}.hub-loading-bar--glow .hub-loading-bar__indicator:after{content:\"\";position:absolute;inset-block:0;inset-inline-end:0;inline-size:var(--hub-loading-bar-height);box-shadow:0 0 var(--hub-loading-bar-glow-blur) var(--hub-loading-bar-glow-spread) var(--hub-loading-bar-glow-color),0 0 calc(var(--hub-loading-bar-glow-blur) / 2) var(--hub-loading-bar-glow-color)}.hub-loading-bar--indeterminate .hub-loading-bar__indicator,.hub-loading-bar--visible.hub-loading-bar--indeterminate .hub-loading-bar__indicator{inline-size:33%;transition:none;animation:hub-loading-bar-sweep var(--hub-loading-bar-indeterminate-speed) ease-in-out infinite}@media(prefers-reduced-motion:reduce){.hub-loading-bar{--hub-loading-bar-indeterminate-speed: 3.2s}}@keyframes hub-loading-bar-sweep{0%{transform:translate(calc(-100% * var(--hub-loading-bar-sweep-direction)))}to{transform:translate(calc(300% * var(--hub-loading-bar-sweep-direction)))}}\n"] }]
|
|
772
|
+
}, template: "<span class=\"hub-loading-bar__indicator\"></span>\n", styles: [":where(.hub-loading-bar){--hub-loading-bar-accent: var(--hub-sys-color-primary, #0d6efd);--hub-loading-bar-height: 3px;--hub-loading-bar-track-bg: transparent;--hub-loading-bar-radius: 0;--hub-loading-bar-speed: .2s;--hub-loading-bar-fade: .3s;--hub-loading-bar-easing: linear;--hub-loading-bar-glow-color: var(--hub-loading-bar-accent);--hub-loading-bar-glow-blur: 10px;--hub-loading-bar-glow-spread: 1px;--hub-loading-bar-indeterminate-speed: 1.6s;--hub-loading-bar-offset: 0px;--hub-loading-bar-z-index: var(--hub-sys-zindex-sticky, 1020);--hub-loading-bar-progress: 0%;--hub-loading-bar-sweep-direction: 1}[dir=rtl] .hub-loading-bar,.hub-loading-bar[dir=rtl]{--hub-loading-bar-sweep-direction: -1}.hub-loading-bar{display:block;position:relative;overflow:hidden;inline-size:100%;block-size:var(--hub-loading-bar-height);background:var(--hub-loading-bar-track-bg);border-radius:var(--hub-loading-bar-radius);opacity:0;pointer-events:none;transition:opacity var(--hub-loading-bar-fade) ease}.hub-loading-bar--visible{opacity:1}.hub-loading-bar--overlay,.hub-loading-bar--fixed{inset-inline:0;z-index:var(--hub-loading-bar-z-index)}.hub-loading-bar--overlay{position:absolute}.hub-loading-bar--fixed{position:fixed}.hub-loading-bar--top{inset-block-start:var(--hub-loading-bar-offset)}.hub-loading-bar--bottom{inset-block-end:var(--hub-loading-bar-offset)}.hub-loading-bar__indicator{display:block;position:relative;inline-size:var(--hub-loading-bar-progress);block-size:100%;background:var(--hub-loading-bar-accent);border-radius:inherit}.hub-loading-bar--visible .hub-loading-bar__indicator{transition:inline-size var(--hub-loading-bar-speed) var(--hub-loading-bar-easing)}.hub-loading-bar--glow .hub-loading-bar__indicator:after{content:\"\";position:absolute;inset-block:0;inset-inline-end:0;inline-size:var(--hub-loading-bar-height);box-shadow:0 0 var(--hub-loading-bar-glow-blur) var(--hub-loading-bar-glow-spread) var(--hub-loading-bar-glow-color),0 0 calc(var(--hub-loading-bar-glow-blur) / 2) var(--hub-loading-bar-glow-color)}.hub-loading-bar--indeterminate .hub-loading-bar__indicator,.hub-loading-bar--visible.hub-loading-bar--indeterminate .hub-loading-bar__indicator{inline-size:33%;transition:none;animation:hub-loading-bar-sweep var(--hub-loading-bar-indeterminate-speed) ease-in-out infinite}@media(prefers-reduced-motion:reduce){.hub-loading-bar{--hub-loading-bar-indeterminate-speed: 3.2s}}@keyframes hub-loading-bar-sweep{0%{transform:translate(calc(-100% * var(--hub-loading-bar-sweep-direction)))}to{transform:translate(calc(300% * var(--hub-loading-bar-sweep-direction)))}}\n"] }]
|
|
748
773
|
}], propDecorators: { mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "placement", required: false }] }], progress: [{ type: i0.Input, args: [{ isSignal: true, alias: "progress", required: false }] }], indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: false }] }], glow: [{ type: i0.Input, args: [{ isSignal: true, alias: "glow", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
|
|
749
774
|
|
|
750
775
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ng-hub-ui-loading.mjs","sources":["../../../projects/loading/src/lib/loading-config.ts","../../../projects/loading/src/lib/components/loading/loading.component.ts","../../../projects/loading/src/lib/components/loading/loading.component.html","../../../projects/loading/src/lib/services/loading.service.ts","../../../projects/loading/src/lib/loading-bar-config.ts","../../../projects/loading/src/lib/services/loading-bar.service.ts","../../../projects/loading/src/lib/components/loading-bar/loading-bar.component.ts","../../../projects/loading/src/lib/components/loading-bar/loading-bar.component.html","../../../projects/loading/src/lib/integrations/loading-bar-interceptor.ts","../../../projects/loading/src/lib/integrations/loading-bar-router.ts","../../../projects/loading/src/public-api.ts","../../../projects/loading/src/ng-hub-ui-loading.ts"],"sourcesContent":["import { EnvironmentProviders, InjectionToken, makeEnvironmentProviders } from '@angular/core';\nimport { HubLoadingConfig } from './models/loading.types';\n\n/**\n * Neutral defaults applied when an application provides no configuration.\n *\n * These are the values documented as each input's default, so overriding the\n * token silently re-bases the whole application without touching a template.\n */\nexport const HUB_LOADING_DEFAULT_CONFIG: HubLoadingConfig = {\n\tmessage: null,\n\tvariant: 'spinner',\n\timage: null,\n\timageAnimation: 'none',\n\tsize: 'md',\n\tcolor: null,\n\tbackdrop: true,\n\tariaLabel: 'Loading'\n};\n\n/**\n * Resolved defaults shared by `<hub-loading>` and `HubLoadingService`.\n *\n * Declared with a root factory so the token is always injectable, even when the\n * application never calls {@link provideHubLoading}.\n */\nexport const HUB_LOADING_CONFIG = new InjectionToken<HubLoadingConfig>('HUB_LOADING_CONFIG', {\n\tprovidedIn: 'root',\n\tfactory: () => HUB_LOADING_DEFAULT_CONFIG\n});\n\n/**\n * Registers application-wide loading defaults — typically the brand image, the\n * preferred variant and a translated label — so individual call sites stay bare.\n *\n * @param config - Values overriding {@link HUB_LOADING_DEFAULT_CONFIG}; omitted keys keep their default.\n * @returns Environment providers for the application bootstrap.\n */\nexport function provideHubLoading(config: Partial<HubLoadingConfig> = {}): EnvironmentProviders {\n\treturn makeEnvironmentProviders([\n\t\t{\n\t\t\tprovide: HUB_LOADING_CONFIG,\n\t\t\tuseValue: { ...HUB_LOADING_DEFAULT_CONFIG, ...config }\n\t\t}\n\t]);\n}\n","import {\n\tbooleanAttribute,\n\tChangeDetectionStrategy,\n\tComponent,\n\tcomputed,\n\tinject,\n\tinput,\n\tViewEncapsulation\n} from '@angular/core';\nimport { resolveHubAccent } from 'ng-hub-ui-utils';\nimport { HUB_LOADING_CONFIG } from '../../loading-config';\nimport { HubLoadingImageAnimation, HubLoadingMode, HubLoadingSize, HubLoadingVariant } from '../../models/loading.types';\n\n/**\n * Activity indicator rendered inline, over its container or over the viewport.\n *\n * Every input defaults to the injected `HUB_LOADING_CONFIG`, so `provideHubLoading()`\n * re-bases an entire application (brand image, variant, translated label) without\n * touching a single template, while a per-instance binding still wins locally.\n *\n * Styles are unencapsulated on purpose: the host carries the `hub-loading` class and\n * the token block, so consumers can retheme the indicator from a global stylesheet —\n * and so the service-mounted overlay, created outside any component's style scope,\n * is still painted.\n *\n * @example\n * ```html\n * <hub-loading variant=\"dots\" message=\"Loading orders…\" />\n *\n * <div style=\"position: relative\">\n * <hub-loading mode=\"overlay\" color=\"primary\" />\n * </div>\n * ```\n */\n@Component({\n\tselector: 'hub-loading',\n\tstandalone: true,\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\tencapsulation: ViewEncapsulation.None,\n\ttemplateUrl: './loading.component.html',\n\tstyleUrl: './loading.component.scss',\n\thost: {\n\t\tclass: 'hub-loading',\n\t\trole: 'status',\n\t\t'aria-live': 'polite',\n\t\t'aria-busy': 'true',\n\t\t'[class]': '_modifierClasses()',\n\t\t'[class.hub-loading--backdrop]': '_showsBackdrop()',\n\t\t'[attr.aria-label]': 'ariaLabel()',\n\t\t'[style.--hub-loading-accent]': '_accent()'\n\t}\n})\nexport class HubLoadingComponent {\n\t/** Application-wide defaults; also the source of every input's default value. */\n\tprivate readonly config = inject(HUB_LOADING_CONFIG);\n\n\t/**\n\t * Placement of the indicator. `overlay` needs a positioned ancestor to cover;\n\t * `fullscreen` is fixed to the viewport and layered at `--hub-loading-z-index`.\n\t */\n\treadonly mode = input<HubLoadingMode>('inline');\n\n\t/** Built-in CSS indicator rendered when no {@link image} is supplied. */\n\treadonly variant = input<HubLoadingVariant>(this.config.variant);\n\n\t/** URL or data URI shown instead of the built-in indicator. */\n\treadonly image = input<string | null>(this.config.image);\n\n\t/** Motion applied to {@link image}; inert while no image is set. */\n\treadonly imageAnimation = input<HubLoadingImageAnimation>(this.config.imageAnimation);\n\n\t/** Text rendered below the indicator. */\n\treadonly message = input<string | null>(this.config.message);\n\n\t/** Size step feeding `--hub-loading-size`; the token remains overridable on its own. */\n\treadonly size = input<HubLoadingSize>(this.config.size);\n\n\t/**\n\t * Accent for the indicator. Accepts a semantic name (`primary`), a CSS colour\n\t * literal (`#0d6efd`, `oklch(...)`) or a `var(...)` reference — normalised by\n\t * `resolveHubAccent()` into the single `--hub-loading-accent` slot.\n\t */\n\treadonly color = input<string | null>(this.config.color);\n\n\t/** Paints the translucent scrim. Ignored in `inline` mode, which covers nothing. */\n\treadonly backdrop = input(this.config.backdrop, { transform: booleanAttribute });\n\n\t/** Accessible label announced by the host's `role=\"status\"` live region. */\n\treadonly ariaLabel = input<string>(this.config.ariaLabel);\n\n\t/** Mode and size modifiers; kept as one binding so a size change cannot drop the mode. */\n\tprotected readonly _modifierClasses = computed(() => `hub-loading--${this.mode()} hub-loading--${this.size()}`);\n\n\t/**\n\t * The scrim only exists where the indicator actually covers something, so an\n\t * inline block never paints a background it would have no reason to own.\n\t */\n\tprotected readonly _showsBackdrop = computed(() => this.backdrop() && this.mode() !== 'inline');\n\n\t/**\n\t * Single accent slot consumed by the stylesheet. `null` leaves the binding off\n\t * entirely, so the token's own cascade default stays in effect.\n\t */\n\tprotected readonly _accent = computed(() => resolveHubAccent(this.color()));\n\n\t/** Motion modifier for the branding image; `none` adds no class at all. */\n\tprotected readonly _imageClasses = computed(() =>\n\t\tthis.imageAnimation() === 'none' ? '' : `hub-loading__image--${this.imageAnimation()}`\n\t);\n}\n","@if (image(); as source) {\n\t<img class=\"hub-loading__image\" [class]=\"_imageClasses()\" [src]=\"source\" alt=\"\" aria-hidden=\"true\" />\n} @else {\n\t@switch (variant()) {\n\t\t@case ('dots') {\n\t\t\t<span class=\"hub-loading__indicator hub-loading__indicator--dots\" aria-hidden=\"true\">\n\t\t\t\t<span class=\"hub-loading__dot\"></span>\n\t\t\t\t<span class=\"hub-loading__dot\"></span>\n\t\t\t\t<span class=\"hub-loading__dot\"></span>\n\t\t\t</span>\n\t\t}\n\t\t@case ('bars') {\n\t\t\t<span class=\"hub-loading__indicator hub-loading__indicator--bars\" aria-hidden=\"true\">\n\t\t\t\t<span class=\"hub-loading__bar\"></span>\n\t\t\t\t<span class=\"hub-loading__bar\"></span>\n\t\t\t\t<span class=\"hub-loading__bar\"></span>\n\t\t\t\t<span class=\"hub-loading__bar\"></span>\n\t\t\t</span>\n\t\t}\n\t\t@case ('pulse') {\n\t\t\t<span class=\"hub-loading__indicator hub-loading__indicator--pulse\" aria-hidden=\"true\"></span>\n\t\t}\n\t\t@case ('ring') {\n\t\t\t<span class=\"hub-loading__indicator hub-loading__indicator--ring\" aria-hidden=\"true\"></span>\n\t\t}\n\t\t@default {\n\t\t\t<span class=\"hub-loading__indicator hub-loading__indicator--spinner\" aria-hidden=\"true\"></span>\n\t\t}\n\t}\n}\n\n@if (message()) {\n\t<p class=\"hub-loading__message\">{{ message() }}</p>\n}\n\n<ng-content />\n","import { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport {\n\tApplicationRef,\n\tComponentRef,\n\tInjectable,\n\tPLATFORM_ID,\n\tSignal,\n\tcomputed,\n\tcreateComponent,\n\tinject,\n\tsignal\n} from '@angular/core';\nimport { HubLoadingComponent } from '../components/loading/loading.component';\nimport { HUB_LOADING_CONFIG } from '../loading-config';\nimport { HubLoadingOptions } from '../models/loading.types';\n\n/**\n * Drives a single application-wide fullscreen loading overlay.\n *\n * Concurrency is handled with a reference counter rather than a boolean, because\n * independent callers overlap constantly (two parallel requests, a resolver plus a\n * component): the overlay appears on the first `show()` and only disappears once\n * every caller has balanced it with a `hide()`. A caller that forgets to hide would\n * strand the overlay, so {@link hideAll} exists as the explicit escape hatch — use it\n * from an error handler or a route change, never as a substitute for balanced calls.\n *\n * Server-side there is no DOM to mount into, so only the counter runs: `isLoading`\n * stays truthful and hydration finds no orphan overlay markup.\n *\n * @example\n * ```typescript\n * private readonly loading = inject(HubLoadingService);\n *\n * async save(): Promise<void> {\n * this.loading.show({ message: 'Saving…' });\n * try {\n * await this.api.save();\n * } finally {\n * this.loading.hide();\n * }\n * }\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class HubLoadingService {\n\tprivate readonly appRef = inject(ApplicationRef);\n\tprivate readonly document = inject(DOCUMENT);\n\tprivate readonly platformId = inject(PLATFORM_ID);\n\tprivate readonly config = inject(HUB_LOADING_CONFIG);\n\n\t/** Number of callers currently requesting the overlay. */\n\tprivate readonly pending = signal(0);\n\n\t/** Live reference to the mounted overlay; `null` whenever nothing is showing. */\n\tprivate overlayRef: ComponentRef<HubLoadingComponent> | null = null;\n\n\t/**\n\t * Options accumulated by the active `show()` / `update()` calls, layered over\n\t * `HUB_LOADING_CONFIG`. Reset once the counter reaches zero so a later overlay\n\t * never inherits a stale message from a finished operation.\n\t */\n\tprivate options: HubLoadingOptions = {};\n\n\t/** True while at least one caller is still waiting. Safe to read during SSR. */\n\treadonly isLoading: Signal<boolean> = computed(() => this.pending() > 0);\n\n\t/**\n\t * Registers one caller and mounts the overlay if it is not up yet.\n\t *\n\t * @param options - Presentation overrides merged over the application defaults;\n\t * only the keys supplied are changed, so nested calls compose instead of resetting.\n\t */\n\tshow(options: HubLoadingOptions = {}): void {\n\t\tthis.mergeOptions(options);\n\t\tthis.pending.update((count) => count + 1);\n\t\tthis.mount();\n\t}\n\n\t/**\n\t * Retires one caller, tearing the overlay down once none are left.\n\t * Extra calls are harmless: the counter is clamped at zero rather than going\n\t * negative, so a stray `hide()` cannot make a later `show()` a no-op.\n\t */\n\thide(): void {\n\t\tthis.pending.update((count) => Math.max(0, count - 1));\n\n\t\tif (this.pending() === 0) {\n\t\t\tthis.unmount();\n\t\t}\n\t}\n\n\t/** Drops every pending caller and removes the overlay immediately. */\n\thideAll(): void {\n\t\tthis.pending.set(0);\n\t\tthis.unmount();\n\t}\n\n\t/**\n\t * Re-dresses the overlay while it stays up — a progress message that changes\n\t * mid-operation, a variant swap — without touching the reference counter.\n\t *\n\t * @param options - Presentation overrides merged over the active ones.\n\t */\n\tupdate(options: HubLoadingOptions): void {\n\t\tthis.mergeOptions(options);\n\t\tthis.applyOptions();\n\t}\n\n\t/**\n\t * Copies only the keys the caller actually supplied.\n\t *\n\t * A plain spread would let an `undefined` property erase a configured default,\n\t * which would make `{ message: undefined }` and `{ message: null }` behave the\n\t * same; here `undefined` means \"leave it alone\" and `null` means \"clear it\".\n\t */\n\tprivate mergeOptions(options: HubLoadingOptions): void {\n\t\tfor (const [key, value] of Object.entries(options)) {\n\t\t\tif (value !== undefined) {\n\t\t\t\t(this.options as Record<string, unknown>)[key] = value;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates the overlay on `document.body` once, outside any component subtree, so\n\t * it is never clipped by an ancestor's `overflow` or stacking context.\n\t */\n\tprivate mount(): void {\n\t\tif (!isPlatformBrowser(this.platformId)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.overlayRef) {\n\t\t\tthis.applyOptions();\n\t\t\treturn;\n\t\t}\n\n\t\t// A `show()` racing application teardown (a destroyed TestBed, an HMR reload)\n\t\t// would otherwise touch a dead environment injector and throw NG0205.\n\t\tif (this.appRef.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst ref = createComponent(HubLoadingComponent, { environmentInjector: this.appRef.injector });\n\t\tthis.overlayRef = ref;\n\t\tthis.appRef.attachView(ref.hostView);\n\t\tthis.document.body.appendChild(ref.location.nativeElement);\n\t\tthis.applyOptions();\n\t}\n\n\t/** Destroys the overlay and forgets the accumulated options. */\n\tprivate unmount(): void {\n\t\tconst ref = this.overlayRef;\n\t\tthis.overlayRef = null;\n\t\tthis.options = {};\n\n\t\tif (!ref) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.appRef.detachView(ref.hostView);\n\t\tref.destroy();\n\t\t// `destroy()` tears down the view but leaves the host node where we put it.\n\t\tref.location.nativeElement.remove();\n\t}\n\n\t/**\n\t * Pushes the resolved options onto the overlay.\n\t *\n\t * Change detection is run by hand: a view attached through `attachView()` sits\n\t * outside the signal graph's \"mark ancestors dirty\" traversal, so it would not\n\t * repaint on its own when an input changes.\n\t */\n\tprivate applyOptions(): void {\n\t\tconst ref = this.overlayRef;\n\n\t\tif (!ref) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst resolved = { ...this.config, ...this.options };\n\t\tref.setInput('mode', 'fullscreen');\n\t\tref.setInput('variant', resolved.variant);\n\t\tref.setInput('image', resolved.image);\n\t\tref.setInput('imageAnimation', resolved.imageAnimation);\n\t\tref.setInput('message', resolved.message);\n\t\tref.setInput('size', resolved.size);\n\t\tref.setInput('color', resolved.color);\n\t\tref.setInput('backdrop', resolved.backdrop);\n\t\tref.setInput('ariaLabel', resolved.ariaLabel);\n\t\tref.changeDetectorRef.detectChanges();\n\t}\n}\n","import { EnvironmentProviders, InjectionToken, makeEnvironmentProviders } from '@angular/core';\nimport { HubLoadingBarConfig } from './models/loading-bar.types';\n\n/**\n * Default trickle curve: large steps early, then progressively smaller ones.\n *\n * The shape is what makes an invented number believable. Moving fast at the start\n * matches the part of a page load that really is fast (the request goes out, the shell\n * responds); slowing near the end matches the part nobody can predict, and leaves room\n * for `complete()` to arrive without the bar having to jump backwards.\n *\n * Exported so a consumer can wrap it rather than rewrite it.\n *\n * @param progress - Current value, 0–100.\n * @returns Amount to add on this tick.\n */\nexport function hubLoadingBarTrickle(progress: number): number {\n\tif (progress < 20) {\n\t\treturn 10;\n\t}\n\tif (progress < 50) {\n\t\treturn 4;\n\t}\n\tif (progress < 80) {\n\t\treturn 2;\n\t}\n\tif (progress < 99) {\n\t\treturn 0.5;\n\t}\n\treturn 0;\n}\n\n/**\n * Neutral defaults applied when an application provides no configuration.\n *\n * These are the values documented as each input's default, so overriding the token\n * silently re-bases the whole application without touching a template.\n */\nexport const HUB_LOADING_BAR_DEFAULT_CONFIG: HubLoadingBarConfig = {\n\tmin: 8,\n\tmax: 99,\n\ttrickleSpeed: 250,\n\ttrickle: true,\n\ttrickleFn: hubLoadingBarTrickle,\n\tdelay: 100,\n\tcompleteDelay: 300,\n\tcolor: null,\n\tglow: true,\n\tariaLabel: 'Loading'\n};\n\n/**\n * Resolved defaults shared by `<hub-loading-bar>` and `HubLoadingBarService`.\n *\n * Declared with a root factory so the token is always injectable, even when the\n * application never calls {@link provideHubLoadingBar}.\n */\nexport const HUB_LOADING_BAR_CONFIG = new InjectionToken<HubLoadingBarConfig>('HUB_LOADING_BAR_CONFIG', {\n\tprovidedIn: 'root',\n\tfactory: () => HUB_LOADING_BAR_DEFAULT_CONFIG\n});\n\n/**\n * Registers application-wide loading-bar defaults — the accent, the pacing, the\n * translated label — so individual call sites stay bare.\n *\n * @param config - Values overriding {@link HUB_LOADING_BAR_DEFAULT_CONFIG}; omitted keys keep their default.\n * @returns Environment providers for the application bootstrap.\n */\nexport function provideHubLoadingBar(config: Partial<HubLoadingBarConfig> = {}): EnvironmentProviders {\n\treturn makeEnvironmentProviders([\n\t\t{\n\t\t\tprovide: HUB_LOADING_BAR_CONFIG,\n\t\t\tuseValue: { ...HUB_LOADING_BAR_DEFAULT_CONFIG, ...config }\n\t\t}\n\t]);\n}\n","import { isPlatformBrowser } from '@angular/common';\nimport { DestroyRef, Injectable, NgZone, PLATFORM_ID, Signal, computed, inject, signal } from '@angular/core';\nimport { HUB_LOADING_BAR_CONFIG } from '../loading-bar-config';\n\n/** The three timers the bar juggles; named so `clearTimer` reads at the call site. */\ntype HubLoadingBarTimer = 'reveal' | 'trickle' | 'complete';\n\n/**\n * Drives the page-level loading bar: the thin strip under the navbar that says\n * \"something is on its way\" without pretending to know how long it will take.\n *\n * Three decisions shape the whole service, and each exists because the naive version is\n * worse:\n *\n * - **Reference counting, not a boolean.** A route change and the three requests its\n * page fires are four independent callers. With a boolean, the first one to finish\n * would take the bar down while the other three were still working. The bar completes\n * when the count reaches zero, and {@link completeAll} is the escape hatch for a caller\n * that never balanced its `start()`.\n * - **A grace period before anything is painted.** Work that finishes within `delay`\n * never shows a bar at all. A cached route that flashes a progress bar for 40 ms reads\n * as a glitch, not as speed.\n * - **A trickle that never reaches the end.** Nothing here knows the real percentage, so\n * the bar advances in shrinking steps and stops at `max`. Only `complete()` may show\n * 100, because only `complete()` knows it is true.\n *\n * Timers run outside the Angular zone. Inside it, a 250 ms interval would trigger change\n * detection for the whole application on every tick and — far worse — would keep\n * `ApplicationRef.isStable` false forever, which hangs server-side rendering. The state\n * is signals, so change detection is still scheduled correctly when a value actually\n * changes. On the server no timer is created at all: the counter stays truthful and the\n * rendered HTML carries no bar to mismatch on hydration.\n *\n * @example\n * ```typescript\n * private readonly bar = inject(HubLoadingBarService);\n *\n * async import(): Promise<void> {\n * this.bar.start();\n * try {\n * await this.api.import();\n * } finally {\n * this.bar.complete();\n * }\n * }\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class HubLoadingBarService {\n\tprivate readonly config = inject(HUB_LOADING_BAR_CONFIG);\n\tprivate readonly zone = inject(NgZone);\n\tprivate readonly platformId = inject(PLATFORM_ID);\n\n\t/** Number of callers currently waiting on something. */\n\tprivate readonly pending = signal(0);\n\n\t/** Current fill, 0–100. */\n\tprivate readonly _progress = signal(0);\n\n\t/** Whether the bar is painted right now; false during the grace period. */\n\tprivate readonly _visible = signal(false);\n\n\t/** Handles of the running timers, so each can be cancelled independently. */\n\tprivate readonly timers: Record<HubLoadingBarTimer, ReturnType<typeof setTimeout> | null> = {\n\t\treveal: null,\n\t\ttrickle: null,\n\t\tcomplete: null\n\t};\n\n\t/** Current fill, 0–100. Bound by `<hub-loading-bar>`; safe to read during SSR. */\n\treadonly progress: Signal<number> = this._progress.asReadonly();\n\n\t/**\n\t * Whether the bar is on screen. Differs from {@link isActive} at both ends of a cycle:\n\t * false while the grace period runs, and still true during the completion tail.\n\t */\n\treadonly isVisible: Signal<boolean> = this._visible.asReadonly();\n\n\t/**\n\t * Whether any caller is still waiting — the honest \"is the page loading?\" question,\n\t * regardless of whether the bar has decided to show itself yet.\n\t */\n\treadonly isActive: Signal<boolean> = computed(() => this.pending() > 0);\n\n\tconstructor() {\n\t\t// A root service outlives most things, but not a TestBed reset or an HMR reload;\n\t\t// an orphan interval would keep ticking against a dead injector.\n\t\tinject(DestroyRef).onDestroy(() => this.clearAllTimers());\n\t}\n\n\t/**\n\t * Registers one caller. The first one starts a cycle; the rest simply join the count.\n\t */\n\tstart(): void {\n\t\tconst wasIdle = this.pending() === 0;\n\t\tthis.pending.update((count) => count + 1);\n\n\t\tif (!wasIdle) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.timers.complete !== null) {\n\t\t\t// Interrupting the completion tail. Drop the bar before rewinding it: the\n\t\t\t// stylesheet only transitions the fill while the bar is visible, so rewinding\n\t\t\t// it on screen would animate the progress running backwards.\n\t\t\tthis.clearTimer('complete');\n\t\t\tthis._visible.set(false);\n\t\t}\n\n\t\tthis._progress.set(this.config.min);\n\n\t\tif (!isPlatformBrowser(this.platformId)) {\n\t\t\treturn;\n\t\t}\n\n\t\t// `delay: 0` has to mean \"paint now\", not \"paint on the next macrotask\". A router\n\t\t// navigation with no async guard settles inside the same task it started in, so a\n\t\t// deferred reveal would be cancelled by `complete()` before it ever ran and the bar\n\t\t// would be unreachable for anyone who opted out of the grace period.\n\t\tif (this.config.delay <= 0) {\n\t\t\tthis.reveal();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.schedule('reveal', this.config.delay, () => this.reveal());\n\t}\n\n\t/**\n\t * Retires one caller. Once none are left the bar runs to 100% and fades away — or, if\n\t * the grace period swallowed the whole operation, disappears without ever having been\n\t * seen.\n\t */\n\tcomplete(): void {\n\t\tthis.pending.update((count) => Math.max(0, count - 1));\n\n\t\tif (this.pending() === 0) {\n\t\t\tthis.finish();\n\t\t}\n\t}\n\n\t/** Drops every pending caller and completes the bar immediately. */\n\tcompleteAll(): void {\n\t\tthis.pending.set(0);\n\t\tthis.finish();\n\t}\n\n\t/**\n\t * Moves the bar to an exact value and reveals it, bypassing the grace period.\n\t *\n\t * For work whose real percentage is known — a file upload, a paged import. The value\n\t * is not capped at `max`, because a caller reporting a true 100 is not guessing;\n\t * finishing the cycle is still {@link complete}'s job.\n\t *\n\t * @param value - Target fill, 0–100. Values outside the range are clamped.\n\t */\n\tset(value: number): void {\n\t\tthis.reveal();\n\t\tthis._progress.set(Math.min(100, Math.max(0, value)));\n\t}\n\n\t/**\n\t * Advances the bar and reveals it, bypassing the grace period.\n\t *\n\t * @param amount - Step to add. Omitted, the configured trickle curve decides, which is\n\t * what makes an unknown wait keep moving without ever arriving.\n\t */\n\tinc(amount?: number): void {\n\t\tthis.reveal();\n\t\tthis.advance(amount);\n\t}\n\n\t/**\n\t * Cancels everything at once: no completion animation, no pending callers, nothing on\n\t * screen. For an error handler that wants the bar gone rather than finished.\n\t */\n\treset(): void {\n\t\tthis.clearAllTimers();\n\t\tthis.pending.set(0);\n\t\tthis._visible.set(false);\n\t\tthis._progress.set(0);\n\t}\n\n\t/** Paints the bar and starts the trickle, if a caller is waiting on one. */\n\tprivate reveal(): void {\n\t\tthis.clearTimer('reveal');\n\t\tthis._visible.set(true);\n\t\tthis.startTrickling();\n\t}\n\n\t/**\n\t * Runs the completion, shared by {@link complete} and {@link completeAll}.\n\t *\n\t * The fill is deliberately left at 100 once the bar is hidden. `start()` rewinds it\n\t * while the bar is invisible, where the stylesheet suppresses the transition, so the\n\t * next cycle begins from `min` without the previous one being seen to unwind.\n\t */\n\tprivate finish(): void {\n\t\tthis.clearTimer('reveal');\n\t\tthis.clearTimer('trickle');\n\n\t\tif (!this._visible()) {\n\t\t\tthis._progress.set(0);\n\t\t\treturn;\n\t\t}\n\n\t\tthis._progress.set(100);\n\t\tthis.schedule('complete', this.config.completeDelay, () => this._visible.set(false));\n\t}\n\n\t/** Starts the trickle interval, unless it is disabled, already running or unneeded. */\n\tprivate startTrickling(): void {\n\t\tif (!this.config.trickle || this.timers.trickle !== null || this.pending() === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!isPlatformBrowser(this.platformId)) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.zone.runOutsideAngular(() => {\n\t\t\tthis.timers.trickle = setInterval(() => this.advance(), this.config.trickleSpeed);\n\t\t});\n\t}\n\n\t/** Adds one step, capped at `max` so the trickle can never claim to be finished. */\n\tprivate advance(amount?: number): void {\n\t\tconst current = this._progress();\n\t\tconst step = amount ?? this.config.trickleFn(current);\n\n\t\tthis._progress.set(Math.min(this.config.max, Math.max(0, current + step)));\n\t}\n\n\t/** Schedules a one-shot timer outside the Angular zone, replacing any previous one. */\n\tprivate schedule(name: HubLoadingBarTimer, delay: number, action: () => void): void {\n\t\tthis.clearTimer(name);\n\n\t\tthis.zone.runOutsideAngular(() => {\n\t\t\tthis.timers[name] = setTimeout(() => {\n\t\t\t\tthis.timers[name] = null;\n\t\t\t\taction();\n\t\t\t}, delay);\n\t\t});\n\t}\n\n\t/** Cancels one timer if it is running. Safe to call for a timer that is not. */\n\tprivate clearTimer(name: HubLoadingBarTimer): void {\n\t\tconst handle = this.timers[name];\n\n\t\tif (handle === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.timers[name] = null;\n\t\t// `setInterval` and `setTimeout` share a handle space in both runtimes, so one\n\t\t// clear covers the repeating trickle and the two one-shots alike.\n\t\tclearTimeout(handle);\n\t\tclearInterval(handle as ReturnType<typeof setInterval>);\n\t}\n\n\t/** Cancels every timer; used by `reset()` and on injector teardown. */\n\tprivate clearAllTimers(): void {\n\t\tthis.clearTimer('reveal');\n\t\tthis.clearTimer('trickle');\n\t\tthis.clearTimer('complete');\n\t}\n}\n","import {\n\tbooleanAttribute,\n\tChangeDetectionStrategy,\n\tComponent,\n\tcomputed,\n\tinject,\n\tinput,\n\tViewEncapsulation\n} from '@angular/core';\nimport { resolveHubAccent } from 'ng-hub-ui-utils';\nimport { HUB_LOADING_BAR_CONFIG } from '../../loading-bar-config';\nimport { HubLoadingBarMode, HubLoadingBarPlacement } from '../../models/loading-bar.types';\nimport { HubLoadingBarService } from '../../services/loading-bar.service';\n\n/**\n * The thin strip that reports page-level progress — the bar under the navbar.\n *\n * By default the component draws whatever {@link HubLoadingBarService} is doing, which is\n * what makes a single `<hub-loading-bar />` in the shell enough for the whole\n * application: the router integration and the HTTP interceptor drive the service, and\n * this element follows. Bind `progress` to take it over instead, for a bar reporting one\n * known quantity — an upload, an import — independently of everything else.\n *\n * The `progress` input therefore has three meanings, and the difference matters:\n * unbound (`undefined`) follows the service; a number drives the bar directly; `null`\n * hides it. This mirrors how `HubLoadingService` already reads `undefined` as \"leave it\n * alone\" and `null` as \"clear it\".\n *\n * Note the deliberate gap in the accessibility contract. While the service is trickling,\n * the number on screen is invented — nothing knows the real percentage of a page load —\n * so `aria-valuenow` is withheld, which is exactly how ARIA spells an indeterminate\n * progressbar. Announcing a made-up \"43%\" would be worse than announcing nothing. The\n * value is published only when a caller has bound a real one.\n *\n * Styles are unencapsulated, like the rest of the library, so a consumer can retheme the\n * bar from a global stylesheet.\n *\n * @example\n * ```html\n * <!-- Hanging off the bottom edge of a navbar, driven by the service -->\n * <nav class=\"navbar position-relative\">\n * …\n * <hub-loading-bar mode=\"overlay\" placement=\"bottom\" />\n * </nav>\n *\n * <!-- Reporting one known quantity -->\n * <hub-loading-bar [progress]=\"uploaded()\" color=\"success\" />\n * ```\n */\n@Component({\n\tselector: 'hub-loading-bar',\n\tstandalone: true,\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\tencapsulation: ViewEncapsulation.None,\n\ttemplateUrl: './loading-bar.component.html',\n\tstyleUrl: './loading-bar.component.scss',\n\thost: {\n\t\tclass: 'hub-loading-bar',\n\t\trole: 'progressbar',\n\t\t'aria-valuemin': '0',\n\t\t'aria-valuemax': '100',\n\t\t'[class]': '_modifierClasses()',\n\t\t'[class.hub-loading-bar--visible]': '_visible()',\n\t\t'[attr.aria-label]': 'ariaLabel()',\n\t\t'[attr.aria-valuenow]': '_announcedValue()',\n\t\t'[attr.aria-hidden]': '_visible() ? null : \"true\"',\n\t\t'[style.--hub-loading-bar-progress]': '_fill()',\n\t\t'[style.--hub-loading-bar-accent]': '_accent()'\n\t}\n})\nexport class HubLoadingBarComponent {\n\t/** Application-wide defaults; also the source of every input's default value. */\n\tprivate readonly config = inject(HUB_LOADING_BAR_CONFIG);\n\n\t/** The shared page-level state this bar renders unless `progress` is bound. */\n\tprivate readonly service = inject(HubLoadingBarService);\n\n\t/**\n\t * Placement of the strip. `overlay` needs a positioned ancestor to attach to;\n\t * `fixed` pins it to the viewport at `--hub-loading-bar-offset`.\n\t */\n\treadonly mode = input<HubLoadingBarMode>('inline');\n\n\t/** Edge the `overlay` and `fixed` modes attach to; `inline` ignores it. */\n\treadonly placement = input<HubLoadingBarPlacement>('top');\n\n\t/**\n\t * Takes the bar over. Leave it unbound to follow {@link HubLoadingBarService}; bind a\n\t * number (0–100) to drive it directly, or `null` to hide it.\n\t */\n\treadonly progress = input<number | null | undefined>(undefined);\n\n\t/**\n\t * Sweeps a fragment back and forth instead of filling.\n\t *\n\t * The honest choice when there is no percentage worth inventing — a long stream, a\n\t * job with no reported stages.\n\t */\n\treadonly indeterminate = input(false, { transform: booleanAttribute });\n\n\t/** Soft glow trailing the leading edge, which is what reads as movement. */\n\treadonly glow = input(this.config.glow, { transform: booleanAttribute });\n\n\t/**\n\t * Accent for the fill. Accepts a semantic name (`primary`), a CSS colour literal or a\n\t * `var(...)` reference — normalised by `resolveHubAccent()` into the single\n\t * `--hub-loading-bar-accent` slot.\n\t */\n\treadonly color = input<string | null>(this.config.color);\n\n\t/** Accessible name for the host's `role=\"progressbar\"`. */\n\treadonly ariaLabel = input<string>(this.config.ariaLabel);\n\n\t/** Whether a caller has taken the bar over rather than following the service. */\n\tprivate readonly _manual = computed(() => this.progress() !== undefined);\n\n\t/** Current fill, from whichever source is in charge. */\n\tprivate readonly _value = computed(() => (this._manual() ? (this.progress() ?? 0) : this.service.progress()));\n\n\t/** Whether the strip is painted at all. */\n\tprotected readonly _visible = computed(() => (this._manual() ? this.progress() !== null : this.service.isVisible()));\n\n\t/** Fill as a CSS length, consumed by the stylesheet's single runtime slot. */\n\tprotected readonly _fill = computed(() => `${this._value()}%`);\n\n\t/**\n\t * The value published to assistive technology: only ever a real one.\n\t *\n\t * `null` removes the attribute, which is how ARIA marks a progressbar indeterminate —\n\t * the correct answer both while the service trickles an invented number and while the\n\t * `indeterminate` sweep is running. A bar that is not painted publishes nothing either:\n\t * the host is `aria-hidden` by then, so a stale value would only ever be misleading.\n\t */\n\tprotected readonly _announcedValue = computed(() =>\n\t\tthis._visible() && this._manual() && !this.indeterminate() ? this._value() : null\n\t);\n\n\t/** Mode and placement modifiers; kept as one binding so neither can drop the other. */\n\tprotected readonly _modifierClasses = computed(() => {\n\t\tconst classes = [`hub-loading-bar--${this.mode()}`];\n\n\t\tif (this.mode() !== 'inline') {\n\t\t\tclasses.push(`hub-loading-bar--${this.placement()}`);\n\t\t}\n\t\tif (this.indeterminate()) {\n\t\t\tclasses.push('hub-loading-bar--indeterminate');\n\t\t}\n\t\tif (this.glow()) {\n\t\t\tclasses.push('hub-loading-bar--glow');\n\t\t}\n\n\t\treturn classes.join(' ');\n\t});\n\n\t/**\n\t * Single accent slot consumed by the stylesheet. `null` leaves the binding off\n\t * entirely, so the token's own cascade default stays in effect.\n\t */\n\tprotected readonly _accent = computed(() => resolveHubAccent(this.color()));\n}\n","<span class=\"hub-loading-bar__indicator\"></span>\n","import { HttpContext, HttpContextToken, HttpInterceptorFn } from '@angular/common/http';\nimport { inject } from '@angular/core';\nimport { finalize } from 'rxjs';\nimport { HubLoadingBarService } from '../services/loading-bar.service';\n\n/**\n * Marks a request as invisible to the loading bar.\n *\n * The escape hatch is not a nicety. A poll on a timer, a heartbeat, an autosave — any\n * request the reader did not ask for — would otherwise hold the bar open forever, and a\n * progress bar that never finishes is worse than none.\n */\nexport const HUB_LOADING_BAR_SKIP = new HttpContextToken<boolean>(() => false);\n\n/**\n * Builds the `HttpContext` that hides one request from the loading bar.\n *\n * @param context - Existing context to extend; a fresh one by default.\n * @returns The context, with the skip flag set.\n *\n * @example\n * ```typescript\n * this.http.get('/api/notifications', { context: withoutHubLoadingBar() });\n * ```\n */\nexport function withoutHubLoadingBar(context: HttpContext = new HttpContext()): HttpContext {\n\treturn context.set(HUB_LOADING_BAR_SKIP, true);\n}\n\n/**\n * Holds the loading bar open for the lifetime of every HTTP request.\n *\n * The bar's reference counter is what makes this safe to combine with the router\n * integration and with hand-written `start()` calls: six parallel requests are six\n * callers, and the bar completes when the last of them does, not the first.\n *\n * `finalize` is the balancing point rather than a `tap` on success, because it also fires\n * when the request errors and when the caller unsubscribes — a cancelled typeahead is the\n * commonest way a naive interceptor strands the bar at 90%.\n *\n * Opt a request out with {@link withoutHubLoadingBar}.\n *\n * @example\n * ```typescript\n * provideHttpClient(withInterceptors([hubLoadingBarInterceptor]))\n * ```\n */\nexport const hubLoadingBarInterceptor: HttpInterceptorFn = (req, next) => {\n\tif (req.context.get(HUB_LOADING_BAR_SKIP)) {\n\t\treturn next(req);\n\t}\n\n\tconst bar = inject(HubLoadingBarService);\n\tbar.start();\n\n\treturn next(req).pipe(finalize(() => bar.complete()));\n};\n","import { DestroyRef, EnvironmentProviders, inject, makeEnvironmentProviders, provideAppInitializer } from '@angular/core';\nimport {\n\tEvent as RouterNavigationEvent,\n\tNavigationCancel,\n\tNavigationEnd,\n\tNavigationError,\n\tNavigationSkipped,\n\tNavigationStart,\n\tRouter\n} from '@angular/router';\nimport { HubLoadingBarService } from '../services/loading-bar.service';\n\n/** Every way a navigation can stop, successful or not. All four must release the bar. */\nfunction isNavigationSettled(event: RouterNavigationEvent): boolean {\n\treturn (\n\t\tevent instanceof NavigationEnd ||\n\t\tevent instanceof NavigationCancel ||\n\t\tevent instanceof NavigationError ||\n\t\tevent instanceof NavigationSkipped\n\t);\n}\n\n/**\n * Drives the loading bar from router navigation, which is the \"page is loading\" the bar\n * is named after: it starts when a navigation begins and completes when it settles —\n * including when it is cancelled by a guard or fails, because a bar left running after a\n * rejected navigation is a bar that never goes away.\n *\n * Navigations are tracked with a flag rather than by pairing events one-to-one. The\n * router's event sequence varies with configuration (a blocking initial navigation, a\n * redirect, a skipped same-URL navigation), and the flag guarantees exactly one\n * `start()` / `complete()` pair per navigation whatever order the events arrive in — a\n * missed `NavigationStart` during bootstrap can no longer leave an unmatched `complete()`\n * decrementing somebody else's count.\n *\n * Combine with {@link hubLoadingBarInterceptor} when routes fetch their own data: the\n * navigation settles as soon as the component is created, so without the interceptor the\n * bar finishes while the page is still empty.\n *\n * @returns Environment providers for the application bootstrap.\n *\n * @example\n * ```typescript\n * bootstrapApplication(AppComponent, {\n * providers: [provideRouter(routes), provideHubLoadingBarRouter()]\n * });\n * ```\n */\nexport function provideHubLoadingBarRouter(): EnvironmentProviders {\n\treturn makeEnvironmentProviders([\n\t\tprovideAppInitializer(() => {\n\t\t\tconst router = inject(Router);\n\t\t\tconst bar = inject(HubLoadingBarService);\n\t\t\tlet navigating = false;\n\n\t\t\tconst subscription = router.events.subscribe((event) => {\n\t\t\t\tif (event instanceof NavigationStart) {\n\t\t\t\t\tif (!navigating) {\n\t\t\t\t\t\tnavigating = true;\n\t\t\t\t\t\tbar.start();\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (isNavigationSettled(event) && navigating) {\n\t\t\t\t\tnavigating = false;\n\t\t\t\t\tbar.complete();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tinject(DestroyRef).onDestroy(() => subscription.unsubscribe());\n\t\t})\n\t]);\n}\n","/** Public API surface of ng-hub-ui-loading. */\nexport { HubLoadingComponent } from './lib/components/loading/loading.component';\nexport { HubLoadingService } from './lib/services/loading.service';\nexport { HUB_LOADING_CONFIG, HUB_LOADING_DEFAULT_CONFIG, provideHubLoading } from './lib/loading-config';\nexport type {\n\tHubLoadingConfig,\n\tHubLoadingImageAnimation,\n\tHubLoadingMode,\n\tHubLoadingOptions,\n\tHubLoadingSize,\n\tHubLoadingVariant\n} from './lib/models/loading.types';\n\nexport { HubLoadingBarComponent } from './lib/components/loading-bar/loading-bar.component';\nexport { HubLoadingBarService } from './lib/services/loading-bar.service';\nexport {\n\tHUB_LOADING_BAR_CONFIG,\n\tHUB_LOADING_BAR_DEFAULT_CONFIG,\n\thubLoadingBarTrickle,\n\tprovideHubLoadingBar\n} from './lib/loading-bar-config';\nexport {\n\tHUB_LOADING_BAR_SKIP,\n\thubLoadingBarInterceptor,\n\twithoutHubLoadingBar\n} from './lib/integrations/loading-bar-interceptor';\nexport { provideHubLoadingBarRouter } from './lib/integrations/loading-bar-router';\nexport type {\n\tHubLoadingBarConfig,\n\tHubLoadingBarMode,\n\tHubLoadingBarPlacement,\n\tHubLoadingBarTrickle\n} from './lib/models/loading-bar.types';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ng-hub-ui-loading.mjs","sources":["../../../projects/loading/src/lib/loading-config.ts","../../../projects/loading/src/lib/components/loading/loading.component.ts","../../../projects/loading/src/lib/components/loading/loading.component.html","../../../projects/loading/src/lib/services/loading.service.ts","../../../projects/loading/src/lib/loading-bar-config.ts","../../../projects/loading/src/lib/services/loading-bar.service.ts","../../../projects/loading/src/lib/components/loading-bar/loading-bar.component.ts","../../../projects/loading/src/lib/components/loading-bar/loading-bar.component.html","../../../projects/loading/src/lib/integrations/loading-bar-interceptor.ts","../../../projects/loading/src/lib/integrations/loading-bar-router.ts","../../../projects/loading/src/public-api.ts","../../../projects/loading/src/ng-hub-ui-loading.ts"],"sourcesContent":["import { EnvironmentProviders, InjectionToken, makeEnvironmentProviders } from '@angular/core';\nimport { HubLoadingConfig } from './models/loading.types';\n\n/**\n * Neutral defaults applied when an application provides no configuration.\n *\n * These are the values documented as each input's default, so overriding the\n * token silently re-bases the whole application without touching a template.\n */\nexport const HUB_LOADING_DEFAULT_CONFIG: HubLoadingConfig = {\n\tmessage: null,\n\tvariant: 'spinner',\n\timage: null,\n\timageAnimation: 'none',\n\tsize: 'md',\n\tcolor: null,\n\tbackdrop: true,\n\tariaLabel: 'Loading'\n};\n\n/**\n * Resolved defaults shared by `<hub-loading>` and `HubLoadingService`.\n *\n * Declared with a root factory so the token is always injectable, even when the\n * application never calls {@link provideHubLoading}.\n */\nexport const HUB_LOADING_CONFIG = new InjectionToken<HubLoadingConfig>('HUB_LOADING_CONFIG', {\n\tprovidedIn: 'root',\n\tfactory: () => HUB_LOADING_DEFAULT_CONFIG\n});\n\n/**\n * Registers application-wide loading defaults — typically the brand image, the\n * preferred variant and a translated label — so individual call sites stay bare.\n *\n * @param config - Values overriding {@link HUB_LOADING_DEFAULT_CONFIG}; omitted keys keep their default.\n * @returns Environment providers for the application bootstrap.\n */\nexport function provideHubLoading(config: Partial<HubLoadingConfig> = {}): EnvironmentProviders {\n\treturn makeEnvironmentProviders([\n\t\t{\n\t\t\tprovide: HUB_LOADING_CONFIG,\n\t\t\tuseValue: { ...HUB_LOADING_DEFAULT_CONFIG, ...config }\n\t\t}\n\t]);\n}\n","import {\n\tbooleanAttribute,\n\tChangeDetectionStrategy,\n\tComponent,\n\tcomputed,\n\tinject,\n\tinput,\n\tViewEncapsulation\n} from '@angular/core';\nimport { resolveHubAccent } from 'ng-hub-ui-utils';\nimport { HUB_LOADING_CONFIG } from '../../loading-config';\nimport { HubLoadingImageAnimation, HubLoadingMode, HubLoadingSize, HubLoadingVariant } from '../../models/loading.types';\n\n/**\n * Activity indicator rendered inline, over its container or over the viewport.\n *\n * Every input defaults to the injected `HUB_LOADING_CONFIG`, so `provideHubLoading()`\n * re-bases an entire application (brand image, variant, translated label) without\n * touching a single template, while a per-instance binding still wins locally.\n *\n * Styles are unencapsulated on purpose: the host carries the `hub-loading` class and\n * the token block, so consumers can retheme the indicator from a global stylesheet —\n * and so the service-mounted overlay, created outside any component's style scope,\n * is still painted.\n *\n * @example\n * ```html\n * <hub-loading variant=\"dots\" message=\"Loading orders…\" />\n *\n * <div style=\"position: relative\">\n * <hub-loading mode=\"overlay\" color=\"primary\" />\n * </div>\n * ```\n */\n@Component({\n\tselector: 'hub-loading',\n\tstandalone: true,\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\tencapsulation: ViewEncapsulation.None,\n\ttemplateUrl: './loading.component.html',\n\tstyleUrl: './loading.component.scss',\n\thost: {\n\t\tclass: 'hub-loading',\n\t\trole: 'status',\n\t\t'aria-live': 'polite',\n\t\t'aria-busy': 'true',\n\t\t'[class]': '_modifierClasses()',\n\t\t'[class.hub-loading--backdrop]': '_showsBackdrop()',\n\t\t'[attr.aria-label]': 'ariaLabel()',\n\t\t'[style.--hub-loading-accent]': '_accent()'\n\t}\n})\nexport class HubLoadingComponent {\n\t/** Application-wide defaults; also the source of every input's default value. */\n\tprivate readonly config = inject(HUB_LOADING_CONFIG);\n\n\t/**\n\t * Placement of the indicator. `overlay` needs a positioned ancestor to cover;\n\t * `fullscreen` is fixed to the viewport and layered at `--hub-loading-z-index`.\n\t */\n\treadonly mode = input<HubLoadingMode>('inline');\n\n\t/** Built-in CSS indicator rendered when no {@link image} is supplied. */\n\treadonly variant = input<HubLoadingVariant>(this.config.variant);\n\n\t/** URL or data URI shown instead of the built-in indicator. */\n\treadonly image = input<string | null>(this.config.image);\n\n\t/** Motion applied to {@link image}; inert while no image is set. */\n\treadonly imageAnimation = input<HubLoadingImageAnimation>(this.config.imageAnimation);\n\n\t/** Text rendered below the indicator. */\n\treadonly message = input<string | null>(this.config.message);\n\n\t/** Size step feeding `--hub-loading-size`; the token remains overridable on its own. */\n\treadonly size = input<HubLoadingSize>(this.config.size);\n\n\t/**\n\t * Accent for the indicator. Accepts a semantic name (`primary`), a CSS colour\n\t * literal (`#0d6efd`, `oklch(...)`) or a `var(...)` reference — normalised by\n\t * `resolveHubAccent()` into the single `--hub-loading-accent` slot.\n\t */\n\treadonly color = input<string | null>(this.config.color);\n\n\t/** Paints the translucent scrim. Ignored in `inline` mode, which covers nothing. */\n\treadonly backdrop = input(this.config.backdrop, { transform: booleanAttribute });\n\n\t/** Accessible label announced by the host's `role=\"status\"` live region. */\n\treadonly ariaLabel = input<string>(this.config.ariaLabel);\n\n\t/** Mode and size modifiers; kept as one binding so a size change cannot drop the mode. */\n\tprotected readonly _modifierClasses = computed(() => `hub-loading--${this.mode()} hub-loading--${this.size()}`);\n\n\t/**\n\t * The scrim only exists where the indicator actually covers something, so an\n\t * inline block never paints a background it would have no reason to own.\n\t */\n\tprotected readonly _showsBackdrop = computed(() => this.backdrop() && this.mode() !== 'inline');\n\n\t/**\n\t * Single accent slot consumed by the stylesheet. `null` leaves the binding off\n\t * entirely, so the token's own cascade default stays in effect.\n\t */\n\tprotected readonly _accent = computed(() => resolveHubAccent(this.color()));\n\n\t/** Motion modifier for the branding image; `none` adds no class at all. */\n\tprotected readonly _imageClasses = computed(() =>\n\t\tthis.imageAnimation() === 'none' ? '' : `hub-loading__image--${this.imageAnimation()}`\n\t);\n}\n","@if (image(); as source) {\n\t<img class=\"hub-loading__image\" [class]=\"_imageClasses()\" [src]=\"source\" alt=\"\" aria-hidden=\"true\" />\n} @else {\n\t@switch (variant()) {\n\t\t@case ('dots') {\n\t\t\t<span class=\"hub-loading__indicator hub-loading__indicator--dots\" aria-hidden=\"true\">\n\t\t\t\t<span class=\"hub-loading__dot\"></span>\n\t\t\t\t<span class=\"hub-loading__dot\"></span>\n\t\t\t\t<span class=\"hub-loading__dot\"></span>\n\t\t\t</span>\n\t\t}\n\t\t@case ('bars') {\n\t\t\t<span class=\"hub-loading__indicator hub-loading__indicator--bars\" aria-hidden=\"true\">\n\t\t\t\t<span class=\"hub-loading__bar\"></span>\n\t\t\t\t<span class=\"hub-loading__bar\"></span>\n\t\t\t\t<span class=\"hub-loading__bar\"></span>\n\t\t\t\t<span class=\"hub-loading__bar\"></span>\n\t\t\t</span>\n\t\t}\n\t\t@case ('pulse') {\n\t\t\t<span class=\"hub-loading__indicator hub-loading__indicator--pulse\" aria-hidden=\"true\"></span>\n\t\t}\n\t\t@case ('ring') {\n\t\t\t<span class=\"hub-loading__indicator hub-loading__indicator--ring\" aria-hidden=\"true\"></span>\n\t\t}\n\t\t@default {\n\t\t\t<span class=\"hub-loading__indicator hub-loading__indicator--spinner\" aria-hidden=\"true\"></span>\n\t\t}\n\t}\n}\n\n@if (message()) {\n\t<p class=\"hub-loading__message\">{{ message() }}</p>\n}\n\n<ng-content />\n","import { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport {\n\tApplicationRef,\n\tComponentRef,\n\tInjectable,\n\tPLATFORM_ID,\n\tSignal,\n\tcomputed,\n\tcreateComponent,\n\tinject,\n\tsignal,\n\tuntracked\n} from '@angular/core';\nimport { HubLoadingComponent } from '../components/loading/loading.component';\nimport { HUB_LOADING_CONFIG } from '../loading-config';\nimport { HubLoadingOptions } from '../models/loading.types';\n\n/**\n * Drives a single application-wide fullscreen loading overlay.\n *\n * Concurrency is handled with a reference counter rather than a boolean, because\n * independent callers overlap constantly (two parallel requests, a resolver plus a\n * component): the overlay appears on the first `show()` and only disappears once\n * every caller has balanced it with a `hide()`. A caller that forgets to hide would\n * strand the overlay, so {@link hideAll} exists as the explicit escape hatch — use it\n * from an error handler or a route change, never as a substitute for balanced calls.\n *\n * Server-side there is no DOM to mount into, so only the counter runs: `isLoading`\n * stays truthful and hydration finds no orphan overlay markup.\n *\n * @example\n * ```typescript\n * private readonly loading = inject(HubLoadingService);\n *\n * async save(): Promise<void> {\n * this.loading.show({ message: 'Saving…' });\n * try {\n * await this.api.save();\n * } finally {\n * this.loading.hide();\n * }\n * }\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class HubLoadingService {\n\tprivate readonly appRef = inject(ApplicationRef);\n\tprivate readonly document = inject(DOCUMENT);\n\tprivate readonly platformId = inject(PLATFORM_ID);\n\tprivate readonly config = inject(HUB_LOADING_CONFIG);\n\n\t/**\n\t * Number of callers currently requesting the overlay.\n\t *\n\t * Read through `untracked` wherever it steers this service's own logic. A caller is not\n\t * necessarily outside a reactive context — `hide()` from inside an `effect()` is ordinary\n\t * code — and a tracked read there subscribes that effect to the counter, so anyone else's\n\t * `show()` re-runs it and retires a reference it never registered, taking the overlay down\n\t * while other callers are still waiting. Only `isLoading` reads it tracked, and that one is\n\t * meant to: it exists to be watched.\n\t */\n\tprivate readonly pending = signal(0);\n\n\t/** Live reference to the mounted overlay; `null` whenever nothing is showing. */\n\tprivate overlayRef: ComponentRef<HubLoadingComponent> | null = null;\n\n\t/**\n\t * Options accumulated by the active `show()` / `update()` calls, layered over\n\t * `HUB_LOADING_CONFIG`. Reset once the counter reaches zero so a later overlay\n\t * never inherits a stale message from a finished operation.\n\t */\n\tprivate options: HubLoadingOptions = {};\n\n\t/** True while at least one caller is still waiting. Safe to read during SSR. */\n\treadonly isLoading: Signal<boolean> = computed(() => this.pending() > 0);\n\n\t/**\n\t * Registers one caller and mounts the overlay if it is not up yet.\n\t *\n\t * @param options - Presentation overrides merged over the application defaults;\n\t * only the keys supplied are changed, so nested calls compose instead of resetting.\n\t */\n\tshow(options: HubLoadingOptions = {}): void {\n\t\tthis.mergeOptions(options);\n\t\tthis.pending.update((count) => count + 1);\n\t\tthis.mount();\n\t}\n\n\t/**\n\t * Retires one caller, tearing the overlay down once none are left.\n\t * Extra calls are harmless: the counter is clamped at zero rather than going\n\t * negative, so a stray `hide()` cannot make a later `show()` a no-op.\n\t */\n\thide(): void {\n\t\tthis.pending.update((count) => Math.max(0, count - 1));\n\n\t\tif (untracked(this.pending) === 0) {\n\t\t\tthis.unmount();\n\t\t}\n\t}\n\n\t/** Drops every pending caller and removes the overlay immediately. */\n\thideAll(): void {\n\t\tthis.pending.set(0);\n\t\tthis.unmount();\n\t}\n\n\t/**\n\t * Re-dresses the overlay while it stays up — a progress message that changes\n\t * mid-operation, a variant swap — without touching the reference counter.\n\t *\n\t * @param options - Presentation overrides merged over the active ones.\n\t */\n\tupdate(options: HubLoadingOptions): void {\n\t\tthis.mergeOptions(options);\n\t\tthis.applyOptions();\n\t}\n\n\t/**\n\t * Copies only the keys the caller actually supplied.\n\t *\n\t * A plain spread would let an `undefined` property erase a configured default,\n\t * which would make `{ message: undefined }` and `{ message: null }` behave the\n\t * same; here `undefined` means \"leave it alone\" and `null` means \"clear it\".\n\t */\n\tprivate mergeOptions(options: HubLoadingOptions): void {\n\t\tfor (const [key, value] of Object.entries(options)) {\n\t\t\tif (value !== undefined) {\n\t\t\t\t(this.options as Record<string, unknown>)[key] = value;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates the overlay on `document.body` once, outside any component subtree, so\n\t * it is never clipped by an ancestor's `overflow` or stacking context.\n\t */\n\tprivate mount(): void {\n\t\tif (!isPlatformBrowser(this.platformId)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.overlayRef) {\n\t\t\tthis.applyOptions();\n\t\t\treturn;\n\t\t}\n\n\t\t// A `show()` racing application teardown (a destroyed TestBed, an HMR reload)\n\t\t// would otherwise touch a dead environment injector and throw NG0205.\n\t\tif (this.appRef.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst ref = createComponent(HubLoadingComponent, { environmentInjector: this.appRef.injector });\n\t\tthis.overlayRef = ref;\n\t\tthis.appRef.attachView(ref.hostView);\n\t\tthis.document.body.appendChild(ref.location.nativeElement);\n\t\tthis.applyOptions();\n\t}\n\n\t/** Destroys the overlay and forgets the accumulated options. */\n\tprivate unmount(): void {\n\t\tconst ref = this.overlayRef;\n\t\tthis.overlayRef = null;\n\t\tthis.options = {};\n\n\t\tif (!ref) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.appRef.detachView(ref.hostView);\n\t\tref.destroy();\n\t\t// `destroy()` tears down the view but leaves the host node where we put it.\n\t\tref.location.nativeElement.remove();\n\t}\n\n\t/**\n\t * Pushes the resolved options onto the overlay.\n\t *\n\t * Change detection is run by hand: a view attached through `attachView()` sits\n\t * outside the signal graph's \"mark ancestors dirty\" traversal, so it would not\n\t * repaint on its own when an input changes.\n\t */\n\tprivate applyOptions(): void {\n\t\tconst ref = this.overlayRef;\n\n\t\tif (!ref) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst resolved = { ...this.config, ...this.options };\n\t\tref.setInput('mode', 'fullscreen');\n\t\tref.setInput('variant', resolved.variant);\n\t\tref.setInput('image', resolved.image);\n\t\tref.setInput('imageAnimation', resolved.imageAnimation);\n\t\tref.setInput('message', resolved.message);\n\t\tref.setInput('size', resolved.size);\n\t\tref.setInput('color', resolved.color);\n\t\tref.setInput('backdrop', resolved.backdrop);\n\t\tref.setInput('ariaLabel', resolved.ariaLabel);\n\t\tref.changeDetectorRef.detectChanges();\n\t}\n}\n","import { EnvironmentProviders, InjectionToken, makeEnvironmentProviders } from '@angular/core';\nimport { HubLoadingBarConfig } from './models/loading-bar.types';\n\n/**\n * Default trickle curve: large steps early, then progressively smaller ones.\n *\n * The shape is what makes an invented number believable. Moving fast at the start\n * matches the part of a page load that really is fast (the request goes out, the shell\n * responds); slowing near the end matches the part nobody can predict, and leaves room\n * for `complete()` to arrive without the bar having to jump backwards.\n *\n * Exported so a consumer can wrap it rather than rewrite it.\n *\n * @param progress - Current value, 0–100.\n * @returns Amount to add on this tick.\n */\nexport function hubLoadingBarTrickle(progress: number): number {\n\tif (progress < 20) {\n\t\treturn 10;\n\t}\n\tif (progress < 50) {\n\t\treturn 4;\n\t}\n\tif (progress < 80) {\n\t\treturn 2;\n\t}\n\tif (progress < 99) {\n\t\treturn 0.5;\n\t}\n\treturn 0;\n}\n\n/**\n * Neutral defaults applied when an application provides no configuration.\n *\n * These are the values documented as each input's default, so overriding the token\n * silently re-bases the whole application without touching a template.\n */\nexport const HUB_LOADING_BAR_DEFAULT_CONFIG: HubLoadingBarConfig = {\n\tmin: 8,\n\tmax: 99,\n\ttrickleSpeed: 250,\n\ttrickle: true,\n\ttrickleFn: hubLoadingBarTrickle,\n\tdelay: 100,\n\tcompleteDelay: 300,\n\tcolor: null,\n\tglow: true,\n\tariaLabel: 'Loading'\n};\n\n/**\n * Resolved defaults shared by `<hub-loading-bar>` and `HubLoadingBarService`.\n *\n * Declared with a root factory so the token is always injectable, even when the\n * application never calls {@link provideHubLoadingBar}.\n */\nexport const HUB_LOADING_BAR_CONFIG = new InjectionToken<HubLoadingBarConfig>('HUB_LOADING_BAR_CONFIG', {\n\tprovidedIn: 'root',\n\tfactory: () => HUB_LOADING_BAR_DEFAULT_CONFIG\n});\n\n/**\n * Registers application-wide loading-bar defaults — the accent, the pacing, the\n * translated label — so individual call sites stay bare.\n *\n * @param config - Values overriding {@link HUB_LOADING_BAR_DEFAULT_CONFIG}; omitted keys keep their default.\n * @returns Environment providers for the application bootstrap.\n */\nexport function provideHubLoadingBar(config: Partial<HubLoadingBarConfig> = {}): EnvironmentProviders {\n\treturn makeEnvironmentProviders([\n\t\t{\n\t\t\tprovide: HUB_LOADING_BAR_CONFIG,\n\t\t\tuseValue: { ...HUB_LOADING_BAR_DEFAULT_CONFIG, ...config }\n\t\t}\n\t]);\n}\n","import { isPlatformBrowser } from '@angular/common';\nimport { DestroyRef, Injectable, NgZone, PLATFORM_ID, Signal, computed, inject, signal, untracked } from '@angular/core';\nimport { HUB_LOADING_BAR_CONFIG } from '../loading-bar-config';\n\n/** The three timers the bar juggles; named so `clearTimer` reads at the call site. */\ntype HubLoadingBarTimer = 'reveal' | 'trickle' | 'complete';\n\n/**\n * Drives the page-level loading bar: the thin strip under the navbar that says\n * \"something is on its way\" without pretending to know how long it will take.\n *\n * Three decisions shape the whole service, and each exists because the naive version is\n * worse:\n *\n * - **Reference counting, not a boolean.** A route change and the three requests its\n * page fires are four independent callers. With a boolean, the first one to finish\n * would take the bar down while the other three were still working. The bar completes\n * when the count reaches zero, and {@link completeAll} is the escape hatch for a caller\n * that never balanced its `start()`.\n * - **A grace period before anything is painted.** Work that finishes within `delay`\n * never shows a bar at all. A cached route that flashes a progress bar for 40 ms reads\n * as a glitch, not as speed.\n * - **A trickle that never reaches the end.** Nothing here knows the real percentage, so\n * the bar advances in shrinking steps and stops at `max`. Only `complete()` may show\n * 100, because only `complete()` knows it is true.\n *\n * Timers run outside the Angular zone. Inside it, a 250 ms interval would trigger change\n * detection for the whole application on every tick and — far worse — would keep\n * `ApplicationRef.isStable` false forever, which hangs server-side rendering. The state\n * is signals, so change detection is still scheduled correctly when a value actually\n * changes. On the server no timer is created at all: the counter stays truthful and the\n * rendered HTML carries no bar to mismatch on hydration.\n *\n * @example\n * ```typescript\n * private readonly bar = inject(HubLoadingBarService);\n *\n * async import(): Promise<void> {\n * this.bar.start();\n * try {\n * await this.api.import();\n * } finally {\n * this.bar.complete();\n * }\n * }\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class HubLoadingBarService {\n\tprivate readonly config = inject(HUB_LOADING_BAR_CONFIG);\n\tprivate readonly zone = inject(NgZone);\n\tprivate readonly platformId = inject(PLATFORM_ID);\n\n\t/** Number of callers currently waiting on something. */\n\t/**\n\t * How many callers are holding the bar up.\n\t *\n\t * Read through `untracked` everywhere it steers this service's own logic. A caller is\n\t * not necessarily outside a reactive context — Angular does not untrack interceptors,\n\t * so a request fired from inside an `effect()` runs `start()` inside that effect — and a\n\t * tracked read there subscribes the caller's effect to this counter. Every later request\n\t * then re-runs it, which is a request loop with the bar as the feedback path. Only\n\t * `isActive` reads it tracked, and that one is meant to: it exists to be watched.\n\t */\n\tprivate readonly pending = signal(0);\n\n\t/** Current fill, 0–100. */\n\tprivate readonly _progress = signal(0);\n\n\t/** Whether the bar is painted right now; false during the grace period. */\n\tprivate readonly _visible = signal(false);\n\n\t/** Handles of the running timers, so each can be cancelled independently. */\n\tprivate readonly timers: Record<HubLoadingBarTimer, ReturnType<typeof setTimeout> | null> = {\n\t\treveal: null,\n\t\ttrickle: null,\n\t\tcomplete: null\n\t};\n\n\t/** Current fill, 0–100. Bound by `<hub-loading-bar>`; safe to read during SSR. */\n\treadonly progress: Signal<number> = this._progress.asReadonly();\n\n\t/**\n\t * Whether the bar is on screen. Differs from {@link isActive} at both ends of a cycle:\n\t * false while the grace period runs, and still true during the completion tail.\n\t */\n\treadonly isVisible: Signal<boolean> = this._visible.asReadonly();\n\n\t/**\n\t * Whether any caller is still waiting — the honest \"is the page loading?\" question,\n\t * regardless of whether the bar has decided to show itself yet.\n\t */\n\treadonly isActive: Signal<boolean> = computed(() => this.pending() > 0);\n\n\tconstructor() {\n\t\t// A root service outlives most things, but not a TestBed reset or an HMR reload;\n\t\t// an orphan interval would keep ticking against a dead injector.\n\t\tinject(DestroyRef).onDestroy(() => this.clearAllTimers());\n\t}\n\n\t/**\n\t * Registers one caller. The first one starts a cycle; the rest simply join the count.\n\t */\n\tstart(): void {\n\t\tconst wasIdle = untracked(this.pending) === 0;\n\t\tthis.pending.update((count) => count + 1);\n\n\t\tif (!wasIdle) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.timers.complete !== null) {\n\t\t\t// Interrupting the completion tail. Drop the bar before rewinding it: the\n\t\t\t// stylesheet only transitions the fill while the bar is visible, so rewinding\n\t\t\t// it on screen would animate the progress running backwards.\n\t\t\tthis.clearTimer('complete');\n\t\t\tthis._visible.set(false);\n\t\t}\n\n\t\tthis._progress.set(this.config.min);\n\n\t\tif (!isPlatformBrowser(this.platformId)) {\n\t\t\treturn;\n\t\t}\n\n\t\t// `delay: 0` has to mean \"paint now\", not \"paint on the next macrotask\". A router\n\t\t// navigation with no async guard settles inside the same task it started in, so a\n\t\t// deferred reveal would be cancelled by `complete()` before it ever ran and the bar\n\t\t// would be unreachable for anyone who opted out of the grace period.\n\t\tif (this.config.delay <= 0) {\n\t\t\tthis.reveal();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.schedule('reveal', this.config.delay, () => this.reveal());\n\t}\n\n\t/**\n\t * Retires one caller. Once none are left the bar runs to 100% and fades away — or, if\n\t * the grace period swallowed the whole operation, disappears without ever having been\n\t * seen.\n\t */\n\tcomplete(): void {\n\t\tthis.pending.update((count) => Math.max(0, count - 1));\n\n\t\tif (untracked(this.pending) === 0) {\n\t\t\tthis.finish();\n\t\t}\n\t}\n\n\t/** Drops every pending caller and completes the bar immediately. */\n\tcompleteAll(): void {\n\t\tthis.pending.set(0);\n\t\tthis.finish();\n\t}\n\n\t/**\n\t * Moves the bar to an exact value and reveals it, bypassing the grace period.\n\t *\n\t * For work whose real percentage is known — a file upload, a paged import. The value\n\t * is not capped at `max`, because a caller reporting a true 100 is not guessing;\n\t * finishing the cycle is still {@link complete}'s job.\n\t *\n\t * @param value - Target fill, 0–100. Values outside the range are clamped.\n\t */\n\tset(value: number): void {\n\t\tthis.reveal();\n\t\tthis._progress.set(Math.min(100, Math.max(0, value)));\n\t}\n\n\t/**\n\t * Advances the bar and reveals it, bypassing the grace period.\n\t *\n\t * @param amount - Step to add. Omitted, the configured trickle curve decides, which is\n\t * what makes an unknown wait keep moving without ever arriving.\n\t */\n\tinc(amount?: number): void {\n\t\tthis.reveal();\n\t\tthis.advance(amount);\n\t}\n\n\t/**\n\t * Cancels everything at once: no completion animation, no pending callers, nothing on\n\t * screen. For an error handler that wants the bar gone rather than finished.\n\t */\n\treset(): void {\n\t\tthis.clearAllTimers();\n\t\tthis.pending.set(0);\n\t\tthis._visible.set(false);\n\t\tthis._progress.set(0);\n\t}\n\n\t/** Paints the bar and starts the trickle, if a caller is waiting on one. */\n\tprivate reveal(): void {\n\t\tthis.clearTimer('reveal');\n\t\tthis._visible.set(true);\n\t\tthis.startTrickling();\n\t}\n\n\t/**\n\t * Runs the completion, shared by {@link complete} and {@link completeAll}.\n\t *\n\t * The fill is deliberately left at 100 once the bar is hidden. `start()` rewinds it\n\t * while the bar is invisible, where the stylesheet suppresses the transition, so the\n\t * next cycle begins from `min` without the previous one being seen to unwind.\n\t */\n\tprivate finish(): void {\n\t\tthis.clearTimer('reveal');\n\t\tthis.clearTimer('trickle');\n\n\t\t// Untracked for the same reason as `pending`: `complete()` and `completeAll()` are\n\t\t// public and reachable from an effect, and a tracked read here would wake that effect\n\t\t// on every later cycle, completing a bar somebody else had just started.\n\t\tif (!untracked(this._visible)) {\n\t\t\tthis._progress.set(0);\n\t\t\treturn;\n\t\t}\n\n\t\tthis._progress.set(100);\n\t\tthis.schedule('complete', this.config.completeDelay, () => this._visible.set(false));\n\t}\n\n\t/** Starts the trickle interval, unless it is disabled, already running or unneeded. */\n\tprivate startTrickling(): void {\n\t\tif (!this.config.trickle || this.timers.trickle !== null || untracked(this.pending) === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!isPlatformBrowser(this.platformId)) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.zone.runOutsideAngular(() => {\n\t\t\tthis.timers.trickle = setInterval(() => this.advance(), this.config.trickleSpeed);\n\t\t});\n\t}\n\n\t/** Adds one step, capped at `max` so the trickle can never claim to be finished. */\n\tprivate advance(amount?: number): void {\n\t\t// Untracked for the same reason as `pending`: `inc()` is public, so this read can happen\n\t\t// inside a caller's effect, and each step would then re-run it — a bar that advances\n\t\t// itself for as long as the guard allows.\n\t\tconst current = untracked(this._progress);\n\t\tconst step = amount ?? this.config.trickleFn(current);\n\n\t\tthis._progress.set(Math.min(this.config.max, Math.max(0, current + step)));\n\t}\n\n\t/** Schedules a one-shot timer outside the Angular zone, replacing any previous one. */\n\tprivate schedule(name: HubLoadingBarTimer, delay: number, action: () => void): void {\n\t\tthis.clearTimer(name);\n\n\t\tthis.zone.runOutsideAngular(() => {\n\t\t\tthis.timers[name] = setTimeout(() => {\n\t\t\t\tthis.timers[name] = null;\n\t\t\t\taction();\n\t\t\t}, delay);\n\t\t});\n\t}\n\n\t/** Cancels one timer if it is running. Safe to call for a timer that is not. */\n\tprivate clearTimer(name: HubLoadingBarTimer): void {\n\t\tconst handle = this.timers[name];\n\n\t\tif (handle === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.timers[name] = null;\n\t\t// `setInterval` and `setTimeout` share a handle space in both runtimes, so one\n\t\t// clear covers the repeating trickle and the two one-shots alike.\n\t\tclearTimeout(handle);\n\t\tclearInterval(handle as ReturnType<typeof setInterval>);\n\t}\n\n\t/** Cancels every timer; used by `reset()` and on injector teardown. */\n\tprivate clearAllTimers(): void {\n\t\tthis.clearTimer('reveal');\n\t\tthis.clearTimer('trickle');\n\t\tthis.clearTimer('complete');\n\t}\n}\n","import {\n\tbooleanAttribute,\n\tChangeDetectionStrategy,\n\tComponent,\n\tcomputed,\n\tinject,\n\tinput,\n\tViewEncapsulation\n} from '@angular/core';\nimport { resolveHubAccent } from 'ng-hub-ui-utils';\nimport { HUB_LOADING_BAR_CONFIG } from '../../loading-bar-config';\nimport { HubLoadingBarMode, HubLoadingBarPlacement } from '../../models/loading-bar.types';\nimport { HubLoadingBarService } from '../../services/loading-bar.service';\n\n/**\n * The thin strip that reports page-level progress — the bar under the navbar.\n *\n * By default the component draws whatever {@link HubLoadingBarService} is doing, which is\n * what makes a single `<hub-loading-bar />` in the shell enough for the whole\n * application: the router integration and the HTTP interceptor drive the service, and\n * this element follows. Bind `progress` to take it over instead, for a bar reporting one\n * known quantity — an upload, an import — independently of everything else.\n *\n * The `progress` input therefore has three meanings, and the difference matters:\n * unbound (`undefined`) follows the service; a number drives the bar directly; `null`\n * hides it. This mirrors how `HubLoadingService` already reads `undefined` as \"leave it\n * alone\" and `null` as \"clear it\".\n *\n * Note the deliberate gap in the accessibility contract. While the service is trickling,\n * the number on screen is invented — nothing knows the real percentage of a page load —\n * so `aria-valuenow` is withheld, which is exactly how ARIA spells an indeterminate\n * progressbar. Announcing a made-up \"43%\" would be worse than announcing nothing. The\n * value is published only when a caller has bound a real one.\n *\n * Styles are unencapsulated, like the rest of the library, so a consumer can retheme the\n * bar from a global stylesheet.\n *\n * @example\n * ```html\n * <!-- Hanging off the bottom edge of a navbar, driven by the service -->\n * <nav class=\"navbar position-relative\">\n * …\n * <hub-loading-bar mode=\"overlay\" placement=\"bottom\" />\n * </nav>\n *\n * <!-- Reporting one known quantity -->\n * <hub-loading-bar [progress]=\"uploaded()\" color=\"success\" />\n * ```\n */\n@Component({\n\tselector: 'hub-loading-bar',\n\tstandalone: true,\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\tencapsulation: ViewEncapsulation.None,\n\ttemplateUrl: './loading-bar.component.html',\n\tstyleUrl: './loading-bar.component.scss',\n\thost: {\n\t\tclass: 'hub-loading-bar',\n\t\trole: 'progressbar',\n\t\t'aria-valuemin': '0',\n\t\t'aria-valuemax': '100',\n\t\t'[class]': '_modifierClasses()',\n\t\t'[class.hub-loading-bar--visible]': '_visible()',\n\t\t'[attr.aria-label]': 'ariaLabel()',\n\t\t'[attr.aria-valuenow]': '_announcedValue()',\n\t\t'[attr.aria-hidden]': '_visible() ? null : \"true\"',\n\t\t'[style.--hub-loading-bar-progress]': '_fill()',\n\t\t'[style.--hub-loading-bar-accent]': '_accent()'\n\t}\n})\nexport class HubLoadingBarComponent {\n\t/** Application-wide defaults; also the source of every input's default value. */\n\tprivate readonly config = inject(HUB_LOADING_BAR_CONFIG);\n\n\t/** The shared page-level state this bar renders unless `progress` is bound. */\n\tprivate readonly service = inject(HubLoadingBarService);\n\n\t/**\n\t * Placement of the strip. `overlay` needs a positioned ancestor to attach to;\n\t * `fixed` pins it to the viewport at `--hub-loading-bar-offset`.\n\t */\n\treadonly mode = input<HubLoadingBarMode>('inline');\n\n\t/** Edge the `overlay` and `fixed` modes attach to; `inline` ignores it. */\n\treadonly placement = input<HubLoadingBarPlacement>('top');\n\n\t/**\n\t * Takes the bar over. Leave it unbound to follow {@link HubLoadingBarService}; bind a\n\t * number (0–100) to drive it directly, or `null` to hide it.\n\t */\n\treadonly progress = input<number | null | undefined>(undefined);\n\n\t/**\n\t * Sweeps a fragment back and forth instead of filling.\n\t *\n\t * The honest choice when there is no percentage worth inventing — a long stream, a\n\t * job with no reported stages.\n\t */\n\treadonly indeterminate = input(false, { transform: booleanAttribute });\n\n\t/** Soft glow trailing the leading edge, which is what reads as movement. */\n\treadonly glow = input(this.config.glow, { transform: booleanAttribute });\n\n\t/**\n\t * Accent for the fill. Accepts a semantic name (`primary`), a CSS colour literal or a\n\t * `var(...)` reference — normalised by `resolveHubAccent()` into the single\n\t * `--hub-loading-bar-accent` slot.\n\t */\n\treadonly color = input<string | null>(this.config.color);\n\n\t/** Accessible name for the host's `role=\"progressbar\"`. */\n\treadonly ariaLabel = input<string>(this.config.ariaLabel);\n\n\t/** Whether a caller has taken the bar over rather than following the service. */\n\tprivate readonly _manual = computed(() => this.progress() !== undefined);\n\n\t/** Current fill, from whichever source is in charge. */\n\tprivate readonly _value = computed(() => (this._manual() ? (this.progress() ?? 0) : this.service.progress()));\n\n\t/** Whether the strip is painted at all. */\n\tprotected readonly _visible = computed(() => (this._manual() ? this.progress() !== null : this.service.isVisible()));\n\n\t/** Fill as a CSS length, consumed by the stylesheet's single runtime slot. */\n\tprotected readonly _fill = computed(() => `${this._value()}%`);\n\n\t/**\n\t * The value published to assistive technology: only ever a real one.\n\t *\n\t * `null` removes the attribute, which is how ARIA marks a progressbar indeterminate —\n\t * the correct answer both while the service trickles an invented number and while the\n\t * `indeterminate` sweep is running. A bar that is not painted publishes nothing either:\n\t * the host is `aria-hidden` by then, so a stale value would only ever be misleading.\n\t */\n\tprotected readonly _announcedValue = computed(() =>\n\t\tthis._visible() && this._manual() && !this.indeterminate() ? this._value() : null\n\t);\n\n\t/** Mode and placement modifiers; kept as one binding so neither can drop the other. */\n\tprotected readonly _modifierClasses = computed(() => {\n\t\tconst classes = [`hub-loading-bar--${this.mode()}`];\n\n\t\tif (this.mode() !== 'inline') {\n\t\t\tclasses.push(`hub-loading-bar--${this.placement()}`);\n\t\t}\n\t\tif (this.indeterminate()) {\n\t\t\tclasses.push('hub-loading-bar--indeterminate');\n\t\t}\n\t\tif (this.glow()) {\n\t\t\tclasses.push('hub-loading-bar--glow');\n\t\t}\n\n\t\treturn classes.join(' ');\n\t});\n\n\t/**\n\t * Single accent slot consumed by the stylesheet. `null` leaves the binding off\n\t * entirely, so the token's own cascade default stays in effect.\n\t */\n\tprotected readonly _accent = computed(() => resolveHubAccent(this.color()));\n}\n","<span class=\"hub-loading-bar__indicator\"></span>\n","import { HttpContext, HttpContextToken, HttpInterceptorFn } from '@angular/common/http';\nimport { inject } from '@angular/core';\nimport { finalize } from 'rxjs';\nimport { HubLoadingBarService } from '../services/loading-bar.service';\n\n/**\n * Marks a request as invisible to the loading bar.\n *\n * The escape hatch is not a nicety. A poll on a timer, a heartbeat, an autosave — any\n * request the reader did not ask for — would otherwise hold the bar open forever, and a\n * progress bar that never finishes is worse than none.\n */\nexport const HUB_LOADING_BAR_SKIP = new HttpContextToken<boolean>(() => false);\n\n/**\n * Builds the `HttpContext` that hides one request from the loading bar.\n *\n * @param context - Existing context to extend; a fresh one by default.\n * @returns The context, with the skip flag set.\n *\n * @example\n * ```typescript\n * this.http.get('/api/notifications', { context: withoutHubLoadingBar() });\n * ```\n */\nexport function withoutHubLoadingBar(context: HttpContext = new HttpContext()): HttpContext {\n\treturn context.set(HUB_LOADING_BAR_SKIP, true);\n}\n\n/**\n * Holds the loading bar open for the lifetime of every HTTP request.\n *\n * The bar's reference counter is what makes this safe to combine with the router\n * integration and with hand-written `start()` calls: six parallel requests are six\n * callers, and the bar completes when the last of them does, not the first.\n *\n * `finalize` is the balancing point rather than a `tap` on success, because it also fires\n * when the request errors and when the caller unsubscribes — a cancelled typeahead is the\n * commonest way a naive interceptor strands the bar at 90%.\n *\n * Opt a request out with {@link withoutHubLoadingBar}.\n *\n * @example\n * ```typescript\n * provideHttpClient(withInterceptors([hubLoadingBarInterceptor]))\n * ```\n */\nexport const hubLoadingBarInterceptor: HttpInterceptorFn = (req, next) => {\n\tif (req.context.get(HUB_LOADING_BAR_SKIP)) {\n\t\treturn next(req);\n\t}\n\n\tconst bar = inject(HubLoadingBarService);\n\tbar.start();\n\n\treturn next(req).pipe(finalize(() => bar.complete()));\n};\n","import { DestroyRef, EnvironmentProviders, inject, makeEnvironmentProviders, provideAppInitializer } from '@angular/core';\nimport {\n\tEvent as RouterNavigationEvent,\n\tNavigationCancel,\n\tNavigationEnd,\n\tNavigationError,\n\tNavigationSkipped,\n\tNavigationStart,\n\tRouter\n} from '@angular/router';\nimport { HubLoadingBarService } from '../services/loading-bar.service';\n\n/** Every way a navigation can stop, successful or not. All four must release the bar. */\nfunction isNavigationSettled(event: RouterNavigationEvent): boolean {\n\treturn (\n\t\tevent instanceof NavigationEnd ||\n\t\tevent instanceof NavigationCancel ||\n\t\tevent instanceof NavigationError ||\n\t\tevent instanceof NavigationSkipped\n\t);\n}\n\n/**\n * Drives the loading bar from router navigation, which is the \"page is loading\" the bar\n * is named after: it starts when a navigation begins and completes when it settles —\n * including when it is cancelled by a guard or fails, because a bar left running after a\n * rejected navigation is a bar that never goes away.\n *\n * Navigations are tracked with a flag rather than by pairing events one-to-one. The\n * router's event sequence varies with configuration (a blocking initial navigation, a\n * redirect, a skipped same-URL navigation), and the flag guarantees exactly one\n * `start()` / `complete()` pair per navigation whatever order the events arrive in — a\n * missed `NavigationStart` during bootstrap can no longer leave an unmatched `complete()`\n * decrementing somebody else's count.\n *\n * Combine with {@link hubLoadingBarInterceptor} when routes fetch their own data: the\n * navigation settles as soon as the component is created, so without the interceptor the\n * bar finishes while the page is still empty.\n *\n * @returns Environment providers for the application bootstrap.\n *\n * @example\n * ```typescript\n * bootstrapApplication(AppComponent, {\n * providers: [provideRouter(routes), provideHubLoadingBarRouter()]\n * });\n * ```\n */\nexport function provideHubLoadingBarRouter(): EnvironmentProviders {\n\treturn makeEnvironmentProviders([\n\t\tprovideAppInitializer(() => {\n\t\t\tconst router = inject(Router);\n\t\t\tconst bar = inject(HubLoadingBarService);\n\t\t\tlet navigating = false;\n\n\t\t\tconst subscription = router.events.subscribe((event) => {\n\t\t\t\tif (event instanceof NavigationStart) {\n\t\t\t\t\tif (!navigating) {\n\t\t\t\t\t\tnavigating = true;\n\t\t\t\t\t\tbar.start();\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (isNavigationSettled(event) && navigating) {\n\t\t\t\t\tnavigating = false;\n\t\t\t\t\tbar.complete();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tinject(DestroyRef).onDestroy(() => subscription.unsubscribe());\n\t\t})\n\t]);\n}\n","/** Public API surface of ng-hub-ui-loading. */\nexport { HubLoadingComponent } from './lib/components/loading/loading.component';\nexport { HubLoadingService } from './lib/services/loading.service';\nexport { HUB_LOADING_CONFIG, HUB_LOADING_DEFAULT_CONFIG, provideHubLoading } from './lib/loading-config';\nexport type {\n\tHubLoadingConfig,\n\tHubLoadingImageAnimation,\n\tHubLoadingMode,\n\tHubLoadingOptions,\n\tHubLoadingSize,\n\tHubLoadingVariant\n} from './lib/models/loading.types';\n\nexport { HubLoadingBarComponent } from './lib/components/loading-bar/loading-bar.component';\nexport { HubLoadingBarService } from './lib/services/loading-bar.service';\nexport {\n\tHUB_LOADING_BAR_CONFIG,\n\tHUB_LOADING_BAR_DEFAULT_CONFIG,\n\thubLoadingBarTrickle,\n\tprovideHubLoadingBar\n} from './lib/loading-bar-config';\nexport {\n\tHUB_LOADING_BAR_SKIP,\n\thubLoadingBarInterceptor,\n\twithoutHubLoadingBar\n} from './lib/integrations/loading-bar-interceptor';\nexport { provideHubLoadingBarRouter } from './lib/integrations/loading-bar-router';\nexport type {\n\tHubLoadingBarConfig,\n\tHubLoadingBarMode,\n\tHubLoadingBarPlacement,\n\tHubLoadingBarTrickle\n} from './lib/models/loading-bar.types';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ng-hub-ui-loading",
|
|
3
|
-
"version": "22.1.
|
|
3
|
+
"version": "22.1.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Customizable loading indicators for Angular: inline block, container overlay or fullscreen, plus a page-level progress bar for the navbar, with CSS-only variants, branding image and programmatic services. Part of the ng-hub-ui family.",
|
|
6
6
|
"author": "Carlos Morcillo <carlos.morcillo@me.com> (https://www.carlosmorcillo.com)",
|
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
"@angular/common": ">=21.0.0",
|
|
28
28
|
"@angular/core": ">=21.0.0",
|
|
29
29
|
"@angular/router": ">=21.0.0",
|
|
30
|
-
"ng-hub-ui-utils": ">=22.8.0"
|
|
30
|
+
"ng-hub-ui-utils": ">=22.8.0",
|
|
31
|
+
"rxjs": ">=7.5.0"
|
|
31
32
|
},
|
|
32
33
|
"dependencies": {
|
|
33
34
|
"tslib": "^2.3.0"
|
|
@@ -165,7 +165,16 @@ declare class HubLoadingService {
|
|
|
165
165
|
private readonly document;
|
|
166
166
|
private readonly platformId;
|
|
167
167
|
private readonly config;
|
|
168
|
-
/**
|
|
168
|
+
/**
|
|
169
|
+
* Number of callers currently requesting the overlay.
|
|
170
|
+
*
|
|
171
|
+
* Read through `untracked` wherever it steers this service's own logic. A caller is not
|
|
172
|
+
* necessarily outside a reactive context — `hide()` from inside an `effect()` is ordinary
|
|
173
|
+
* code — and a tracked read there subscribes that effect to the counter, so anyone else's
|
|
174
|
+
* `show()` re-runs it and retires a reference it never registered, taking the overlay down
|
|
175
|
+
* while other callers are still waiting. Only `isLoading` reads it tracked, and that one is
|
|
176
|
+
* meant to: it exists to be watched.
|
|
177
|
+
*/
|
|
169
178
|
private readonly pending;
|
|
170
179
|
/** Live reference to the mounted overlay; `null` whenever nothing is showing. */
|
|
171
180
|
private overlayRef;
|
|
@@ -469,6 +478,16 @@ declare class HubLoadingBarService {
|
|
|
469
478
|
private readonly zone;
|
|
470
479
|
private readonly platformId;
|
|
471
480
|
/** Number of callers currently waiting on something. */
|
|
481
|
+
/**
|
|
482
|
+
* How many callers are holding the bar up.
|
|
483
|
+
*
|
|
484
|
+
* Read through `untracked` everywhere it steers this service's own logic. A caller is
|
|
485
|
+
* not necessarily outside a reactive context — Angular does not untrack interceptors,
|
|
486
|
+
* so a request fired from inside an `effect()` runs `start()` inside that effect — and a
|
|
487
|
+
* tracked read there subscribes the caller's effect to this counter. Every later request
|
|
488
|
+
* then re-runs it, which is a request loop with the bar as the feedback path. Only
|
|
489
|
+
* `isActive` reads it tracked, and that one is meant to: it exists to be watched.
|
|
490
|
+
*/
|
|
472
491
|
private readonly pending;
|
|
473
492
|
/** Current fill, 0–100. */
|
|
474
493
|
private readonly _progress;
|