ng-hub-ui-loading 22.2.2 → 22.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +154 -134
- package/fesm2022/ng-hub-ui-loading.mjs +68 -5
- package/fesm2022/ng-hub-ui-loading.mjs.map +1 -1
- package/package.json +4 -4
- package/types/ng-hub-ui-loading.d.ts +28 -4
package/README.md
CHANGED
|
@@ -76,13 +76,13 @@ and that can render in flow, over its own container, or over the whole viewport.
|
|
|
76
76
|
|
|
77
77
|
### When to reach for which library
|
|
78
78
|
|
|
79
|
-
| Package
|
|
80
|
-
|
|
|
81
|
-
| **`ng-hub-ui-loading`**
|
|
82
|
-
| [`ng-hub-ui-skeleton`](https://www.npmjs.com/package/ng-hub-ui-skeleton) | You already know the shape of what is coming and want the layout to hold its place — structural shimmer placeholders instead of a spinner.
|
|
83
|
-
| [`ng-hub-ui-metrics`](https://www.npmjs.com/package/ng-hub-ui-metrics)
|
|
79
|
+
| Package | Use it when |
|
|
80
|
+
| ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
81
|
+
| **`ng-hub-ui-loading`** | You cannot say how far along the work is, and the shape of the result does not matter yet. An activity indicator — in place, over the busy container, or over the whole app. |
|
|
82
|
+
| [`ng-hub-ui-skeleton`](https://www.npmjs.com/package/ng-hub-ui-skeleton) | You already know the shape of what is coming and want the layout to hold its place — structural shimmer placeholders instead of a spinner. |
|
|
83
|
+
| [`ng-hub-ui-metrics`](https://www.npmjs.com/package/ng-hub-ui-metrics) | You know the progress figure — a determinate progress bar, meter or ring that reports a value. |
|
|
84
84
|
|
|
85
|
-
> **`<hub-loading-bar>` versus `<hub-progress>`.** They look alike and answer different questions. `hub-progress`, in `ng-hub-ui-metrics`,
|
|
85
|
+
> **`<hub-loading-bar>` versus `<hub-progress>`.** They look alike and answer different questions. `hub-progress`, in `ng-hub-ui-metrics`, _displays a value you already know_: it is a data component, and its number is true. `hub-loading-bar` reports that something is happening when nobody knows how long it will take — it invents the number and never lets it reach the end. Use the metrics one for an upload that reports bytes; use this one for the strip under the navbar.
|
|
86
86
|
|
|
87
87
|
The three compose: a skeleton for the list that is arriving, a `<hub-loading mode="overlay">`
|
|
88
88
|
over the panel being refreshed, and a `<hub-progress>` for the upload that reports bytes.
|
|
@@ -94,7 +94,7 @@ over the panel being refreshed, and a `<hub-progress>` for the upload that repor
|
|
|
94
94
|
- **Image / logo support** — swap the indicator for your own brand asset and animate it with `spin` or `pulse`.
|
|
95
95
|
- **Optional message and projected content** — a caption under the indicator plus an `<ng-content>` slot for anything else.
|
|
96
96
|
- **Programmatic overlays** — `HubLoadingService` mounts a fullscreen `<hub-loading>` on demand, with reference-counted `show()` / `hide()` so concurrent tasks cannot dismiss each other's overlay.
|
|
97
|
-
- **Application-wide defaults** — `provideHubLoading()` re-bases every input's default, for the service
|
|
97
|
+
- **Application-wide defaults** — `provideHubLoading()` re-bases every input's default, for the service _and_ for every `<hub-loading>` in a template, without touching a single markup file.
|
|
98
98
|
- **Any accent colour** — `color` accepts a semantic design-system name, a hex value, `oklch()` or a `var(...)` reference, resolved through `resolveHubAccent()` from `ng-hub-ui-utils`.
|
|
99
99
|
- **CSS-variable theming** — every colour, dimension and speed is a `--hub-loading-*` custom property, with a `hub-loading-theme()` Sass mixin for one-call re-skinning.
|
|
100
100
|
- **Accessible by default** — `role="status"`, `aria-live="polite"` and `aria-busy="true"`, with a configurable `ariaLabel` and a `prefers-reduced-motion` treatment that calms the motion instead of freezing it.
|
|
@@ -170,7 +170,7 @@ while the refresh runs.
|
|
|
170
170
|
<article>…already rendered content…</article>
|
|
171
171
|
|
|
172
172
|
@if (refreshing()) {
|
|
173
|
-
|
|
173
|
+
<hub-loading mode="overlay" variant="ring" message="Refreshing…" />
|
|
174
174
|
}
|
|
175
175
|
</section>
|
|
176
176
|
```
|
|
@@ -182,10 +182,29 @@ component owns the state, or let [`HubLoadingService`](#-programmatic-api) mount
|
|
|
182
182
|
|
|
183
183
|
```html
|
|
184
184
|
@if (booting()) {
|
|
185
|
-
|
|
185
|
+
<hub-loading mode="fullscreen" variant="pulse" message="Starting up…" />
|
|
186
186
|
}
|
|
187
187
|
```
|
|
188
188
|
|
|
189
|
+
**It moves to `<body>` to get there.** `position: fixed` only measures from the viewport
|
|
190
|
+
while no ancestor applies layout containment, a transform or a filter, and only paints over
|
|
191
|
+
the page while no ancestor opens a stacking context — neither of which a page can promise.
|
|
192
|
+
Written inside a card with a `transform`, or inside a shell that isolates its stacking
|
|
193
|
+
context, the indicator would cover that box instead of the window. So it leaves the subtree,
|
|
194
|
+
exactly as `HubLoadingService` and `hub-select` already do.
|
|
195
|
+
|
|
196
|
+
`appendTo` names the target; it defaults to `'body'`, takes any CSS selector, and takes
|
|
197
|
+
`null` to leave the indicator where the template puts it. A selector that matches nothing
|
|
198
|
+
also leaves it in place. `inline` and `overlay` are never moved.
|
|
199
|
+
|
|
200
|
+
```html
|
|
201
|
+
<hub-loading mode="fullscreen" appendTo="#overlay-root" /> <hub-loading mode="fullscreen" [appendTo]="null" />
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
> The element moves, the component does not: a `viewChild` still finds it, inputs and
|
|
205
|
+
> projected content work as before. What no longer reaches it is a stylesheet rule written
|
|
206
|
+
> against an ancestor, and a `--hub-*` token set on an ancestor rather than on `:root`.
|
|
207
|
+
|
|
189
208
|
### Backdrop
|
|
190
209
|
|
|
191
210
|
`backdrop` paints the translucent layer behind the indicator. It applies to `overlay`
|
|
@@ -199,13 +218,13 @@ and `fullscreen` only — an inline block has nothing to cover — and is on by
|
|
|
199
218
|
|
|
200
219
|
Five indicators, all drawn with CSS. Pick with the `variant` input.
|
|
201
220
|
|
|
202
|
-
| Variant
|
|
203
|
-
|
|
|
204
|
-
| `spinner` | Rotating arc (the default).
|
|
205
|
-
| `dots`
|
|
206
|
-
| `bars`
|
|
207
|
-
| `pulse`
|
|
208
|
-
| `ring`
|
|
221
|
+
| Variant | Shape |
|
|
222
|
+
| --------- | ---------------------------------------- |
|
|
223
|
+
| `spinner` | Rotating arc (the default). |
|
|
224
|
+
| `dots` | Three dots pulsing in sequence. |
|
|
225
|
+
| `bars` | Bars rising and falling. |
|
|
226
|
+
| `pulse` | A single expanding, fading disc. |
|
|
227
|
+
| `ring` | A full ring with a travelling highlight. |
|
|
209
228
|
|
|
210
229
|
```html
|
|
211
230
|
<hub-loading variant="dots" />
|
|
@@ -238,11 +257,11 @@ case being a product logo on the boot screen. `imageAnimation` gives it motion.
|
|
|
238
257
|
<hub-loading mode="fullscreen" image="/assets/logo.svg" imageAnimation="pulse" message="Preparing your workspace…" />
|
|
239
258
|
```
|
|
240
259
|
|
|
241
|
-
| `imageAnimation` | Effect
|
|
242
|
-
|
|
|
243
|
-
| `none`
|
|
244
|
-
| `spin`
|
|
245
|
-
| `pulse`
|
|
260
|
+
| `imageAnimation` | Effect |
|
|
261
|
+
| ---------------- | ---------------------------- |
|
|
262
|
+
| `none` | Static image (the default). |
|
|
263
|
+
| `spin` | Continuous rotation. |
|
|
264
|
+
| `pulse` | Rhythmic scale/opacity beat. |
|
|
246
265
|
|
|
247
266
|
Size the asset with `--hub-loading-image-size`, and use `--hub-loading-speed` to keep the
|
|
248
267
|
animation in step with the rest of your brand's motion.
|
|
@@ -327,7 +346,7 @@ readonly busy = this.loading.isLoading; // Signal<boolean>
|
|
|
327
346
|
|
|
328
347
|
Register the provider once to re-base the defaults for the whole application — the brand
|
|
329
348
|
image, the preferred variant, a translated label — instead of repeating them at each call
|
|
330
|
-
site. It reaches **both** consumers: the service's overlays
|
|
349
|
+
site. It reaches **both** consumers: the service's overlays _and_ every `<hub-loading>`
|
|
331
350
|
written in a template, because each component input falls back to the same configuration.
|
|
332
351
|
A per-instance binding still wins locally, and individual `show()` / `update()` options are
|
|
333
352
|
merged on top.
|
|
@@ -356,8 +375,8 @@ default below.
|
|
|
356
375
|
|
|
357
376
|
## 📊 Page Progress Bar
|
|
358
377
|
|
|
359
|
-
`<hub-loading-bar>` is the other half of "something is happening": not
|
|
360
|
-
|
|
378
|
+
`<hub-loading-bar>` is the other half of "something is happening": not _this region is
|
|
379
|
+
busy_, but _the page itself is on its way_. It is the thin strip you already know from
|
|
361
380
|
under a navbar, and it is driven by `HubLoadingBarService`.
|
|
362
381
|
|
|
363
382
|
### The three decisions that make it believable
|
|
@@ -466,17 +485,18 @@ And when there is no percentage worth inventing, sweep instead of filling:
|
|
|
466
485
|
|
|
467
486
|
Selector: `hub-loading`. Standalone, `OnPush`, signal inputs.
|
|
468
487
|
|
|
469
|
-
| Input
|
|
470
|
-
|
|
|
471
|
-
| `mode`
|
|
472
|
-
| `variant`
|
|
473
|
-
| `image`
|
|
474
|
-
| `imageAnimation` | `'none' \| 'spin' \| 'pulse'`
|
|
475
|
-
| `message`
|
|
476
|
-
| `size`
|
|
477
|
-
| `color`
|
|
478
|
-
| `backdrop`
|
|
479
|
-
| `ariaLabel`
|
|
488
|
+
| Input | Type | Default | Description |
|
|
489
|
+
| ---------------- | ---------------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
490
|
+
| `mode` | `'inline' \| 'overlay' \| 'fullscreen'` | `'inline'` | Where the block paints. `overlay` is absolutely positioned over the parent (which needs `position: relative`); `fullscreen` is fixed to the viewport. |
|
|
491
|
+
| `variant` | `'spinner' \| 'dots' \| 'bars' \| 'pulse' \| 'ring'` | `'spinner'` | Which pure-CSS indicator to draw. Ignored when `image` is set. |
|
|
492
|
+
| `image` | `string \| null` | `null` | URL or data URI rendered instead of the built-in indicator. |
|
|
493
|
+
| `imageAnimation` | `'none' \| 'spin' \| 'pulse'` | `'none'` | Animation applied to `image`. |
|
|
494
|
+
| `message` | `string \| null` | `null` | Text rendered under the indicator. |
|
|
495
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Indicator scale; maps onto `--hub-loading-size`, which always overrides it. |
|
|
496
|
+
| `color` | `string \| null` | `null` | Accent colour: semantic name, hex, `rgb()`, `oklch()` or `var(...)`. Resolved with `resolveHubAccent()`. |
|
|
497
|
+
| `backdrop` | `boolean` | `true` | Translucent layer behind the indicator. Applies to `overlay` and `fullscreen` only. Read with `booleanAttribute`, so the bare `backdrop` attribute also works. |
|
|
498
|
+
| `ariaLabel` | `string` | `'Loading'` | Accessible name of the status region. |
|
|
499
|
+
| `appendTo` | `string \| null` | `'body'` | CSS selector of the element a `fullscreen` indicator is re-parented to, so it is not trapped by an ancestor's containment or stacking context. `null` keeps it where it is declared; a selector that matches nothing does the same. Ignored for `inline` and `overlay`. |
|
|
480
500
|
|
|
481
501
|
This component has no outputs. Content projected into it renders below the message.
|
|
482
502
|
|
|
@@ -487,13 +507,13 @@ This component has no outputs. Content projected into it renders below the messa
|
|
|
487
507
|
|
|
488
508
|
Injectable (`providedIn: 'root'`). Drives a single fullscreen overlay attached to `document.body`.
|
|
489
509
|
|
|
490
|
-
| Member
|
|
491
|
-
|
|
|
492
|
-
| `show`
|
|
493
|
-
| `hide`
|
|
494
|
-
| `hideAll`
|
|
495
|
-
| `update`
|
|
496
|
-
| `isLoading` | `Signal<boolean>`
|
|
510
|
+
| Member | Signature | Description |
|
|
511
|
+
| ----------- | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
512
|
+
| `show` | `(options?: HubLoadingOptions) => void` | Increments the counter and creates the overlay if it is not mounted yet. |
|
|
513
|
+
| `hide` | `() => void` | Decrements the counter; destroys the overlay when it reaches zero. |
|
|
514
|
+
| `hideAll` | `() => void` | Forces the counter to zero and destroys the overlay. |
|
|
515
|
+
| `update` | `(options: HubLoadingOptions) => void` | Applies new options to the visible overlay. |
|
|
516
|
+
| `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. |
|
|
497
517
|
|
|
498
518
|
### `provideHubLoading(config?)`
|
|
499
519
|
|
|
@@ -511,16 +531,16 @@ The visual options accepted by `show()` and `update()`, and by `provideHubLoadin
|
|
|
511
531
|
application-wide defaults. They mirror the component inputs, minus `mode` — a programmatic
|
|
512
532
|
overlay is always fullscreen.
|
|
513
533
|
|
|
514
|
-
| Option
|
|
515
|
-
|
|
|
516
|
-
| `variant`
|
|
517
|
-
| `image`
|
|
518
|
-
| `imageAnimation` | `'none' \| 'spin' \| 'pulse'`
|
|
519
|
-
| `message`
|
|
520
|
-
| `size`
|
|
521
|
-
| `color`
|
|
522
|
-
| `backdrop`
|
|
523
|
-
| `ariaLabel`
|
|
534
|
+
| Option | Type | Description |
|
|
535
|
+
| ---------------- | ---------------------------------------------------- | --------------------------------------- |
|
|
536
|
+
| `variant` | `'spinner' \| 'dots' \| 'bars' \| 'pulse' \| 'ring'` | Indicator to draw. |
|
|
537
|
+
| `image` | `string \| null` | Image or logo replacing the indicator. |
|
|
538
|
+
| `imageAnimation` | `'none' \| 'spin' \| 'pulse'` | Animation applied to `image`. |
|
|
539
|
+
| `message` | `string \| null` | Text under the indicator. |
|
|
540
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | Indicator scale. |
|
|
541
|
+
| `color` | `string \| null` | Accent colour. |
|
|
542
|
+
| `backdrop` | `boolean` | Translucent layer behind the indicator. |
|
|
543
|
+
| `ariaLabel` | `string` | Accessible name of the status region. |
|
|
524
544
|
|
|
525
545
|
`HubLoadingConfig` is the same shape with every member required — it is what the injection
|
|
526
546
|
token holds once resolved.
|
|
@@ -529,15 +549,15 @@ token holds once resolved.
|
|
|
529
549
|
|
|
530
550
|
Selector: `hub-loading-bar`. Standalone, `OnPush`, signal inputs.
|
|
531
551
|
|
|
532
|
-
| Input
|
|
533
|
-
|
|
|
534
|
-
| `mode`
|
|
535
|
-
| `placement`
|
|
536
|
-
| `progress`
|
|
537
|
-
| `indeterminate` | `boolean`
|
|
538
|
-
| `glow`
|
|
539
|
-
| `color`
|
|
540
|
-
| `ariaLabel`
|
|
552
|
+
| Input | Type | Default | Description |
|
|
553
|
+
| --------------- | ---------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
554
|
+
| `mode` | `'inline' \| 'overlay' \| 'fixed'` | `'inline'` | Where the strip sits. `inline` reserves its own row in the flow; `overlay` is absolutely positioned against the nearest positioned ancestor; `fixed` is pinned to the viewport at `--hub-loading-bar-offset`. |
|
|
555
|
+
| `placement` | `'top' \| 'bottom'` | `'top'` | Edge the `overlay` and `fixed` modes attach to. `inline` ignores it. |
|
|
556
|
+
| `progress` | `number \| null \| undefined` | `undefined` | Three meanings. Unbound: follow `HubLoadingBarService`. A number (0–100): drive the bar directly, and publish it as `aria-valuenow`. `null`: hide the bar. |
|
|
557
|
+
| `indeterminate` | `boolean` | `false` | Sweep a fragment across instead of filling. Read with `booleanAttribute`, so the bare attribute works. |
|
|
558
|
+
| `glow` | `boolean` | `true` | Soft glow trailing the leading edge. |
|
|
559
|
+
| `color` | `string \| null` | `null` | Accent for the fill: semantic name, hex, `oklch()` or `var(...)`. Resolved with `resolveHubAccent()`. |
|
|
560
|
+
| `ariaLabel` | `string` | `'Loading'` | Accessible name of the progressbar. |
|
|
541
561
|
|
|
542
562
|
This component has no outputs and projects no content.
|
|
543
563
|
|
|
@@ -550,17 +570,17 @@ Injectable (`providedIn: 'root'`). Owns the shared page-progress state that ever
|
|
|
550
570
|
`<hub-loading-bar>` renders. Provide it on a component instead to give one bar its own
|
|
551
571
|
state.
|
|
552
572
|
|
|
553
|
-
| Member
|
|
554
|
-
|
|
|
555
|
-
| `start`
|
|
556
|
-
| `complete`
|
|
557
|
-
| `completeAll` | `() => void`
|
|
558
|
-
| `set`
|
|
559
|
-
| `inc`
|
|
560
|
-
| `reset`
|
|
561
|
-
| `progress`
|
|
562
|
-
| `isActive`
|
|
563
|
-
| `isVisible`
|
|
573
|
+
| Member | Signature | Description |
|
|
574
|
+
| ------------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
575
|
+
| `start` | `() => void` | Registers one caller. The first begins a cycle — after the grace period, not immediately. |
|
|
576
|
+
| `complete` | `() => void` | Retires one caller. At zero the bar runs to 100% and fades, or disappears unseen if it never got painted. |
|
|
577
|
+
| `completeAll` | `() => void` | Drops every pending caller and completes the bar at once. |
|
|
578
|
+
| `set` | `(value: number) => void` | Moves the bar to an exact value and reveals it without waiting out the grace period. Clamped to 0–100, not to `max`. |
|
|
579
|
+
| `inc` | `(amount?: number) => void` | Advances the bar and reveals it. Without an amount the configured trickle curve decides. Capped at `max`. |
|
|
580
|
+
| `reset` | `() => void` | Cancels everything: no completion animation, no pending callers, nothing on screen. |
|
|
581
|
+
| `progress` | `Signal<number>` | Current fill, 0–100. |
|
|
582
|
+
| `isActive` | `Signal<boolean>` | Whether any caller is still waiting — true even during the grace period. |
|
|
583
|
+
| `isVisible` | `Signal<boolean>` | Whether the bar is actually painted — false during the grace period, still true through the completion tail. |
|
|
564
584
|
|
|
565
585
|
### `provideHubLoadingBar(config?)`
|
|
566
586
|
|
|
@@ -574,18 +594,18 @@ function provideHubLoadingBar(config?: Partial<HubLoadingBarConfig>): Environmen
|
|
|
574
594
|
|
|
575
595
|
### `HubLoadingBarConfig`
|
|
576
596
|
|
|
577
|
-
| Key
|
|
578
|
-
|
|
|
579
|
-
| `min`
|
|
580
|
-
| `max`
|
|
581
|
-
| `trickleSpeed`
|
|
582
|
-
| `trickle`
|
|
583
|
-
| `trickleFn`
|
|
584
|
-
| `delay`
|
|
585
|
-
| `completeDelay` | `number`
|
|
586
|
-
| `color`
|
|
587
|
-
| `glow`
|
|
588
|
-
| `ariaLabel`
|
|
597
|
+
| Key | Type | Default | Description |
|
|
598
|
+
| --------------- | ------------------------------ | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
599
|
+
| `min` | `number` | `8` | Value the bar jumps to when it appears. Never zero — an empty bar reads as a bar that is not working. |
|
|
600
|
+
| `max` | `number` | `99` | Ceiling the trickle may not cross, so it cannot promise an ending it does not know about. |
|
|
601
|
+
| `trickleSpeed` | `number` | `250` | Milliseconds between trickle ticks. |
|
|
602
|
+
| `trickle` | `boolean` | `true` | Whether the bar advances on its own while it waits. |
|
|
603
|
+
| `trickleFn` | `(progress: number) => number` | `hubLoadingBarTrickle` | Step function. The exported default returns 10 / 4 / 2 / 0.5 as the bar fills. |
|
|
604
|
+
| `delay` | `number` | `100` | Grace period before anything is painted. Work finishing inside it shows no bar. `0` reveals the bar synchronously, so work that settles within its own task is still shown. |
|
|
605
|
+
| `completeDelay` | `number` | `300` | How long the completed bar stays at 100% before fading. Wants to be at least `--hub-loading-bar-speed`. |
|
|
606
|
+
| `color` | `string \| null` | `null` | Default accent. |
|
|
607
|
+
| `glow` | `boolean` | `true` | Default glow. |
|
|
608
|
+
| `ariaLabel` | `string` | `'Loading'` | Default accessible name. |
|
|
589
609
|
|
|
590
610
|
### `provideHubLoadingBarRouter()`
|
|
591
611
|
|
|
@@ -632,19 +652,19 @@ it exactly as before, and a custom property set there inherits down to every ele
|
|
|
632
652
|
The overlay `HubLoadingService` mounts on `document.body` is a real component instance created
|
|
633
653
|
through `createComponent()`, so it carries this stylesheet with it.
|
|
634
654
|
|
|
635
|
-
| Variable
|
|
636
|
-
|
|
|
637
|
-
| `--hub-loading-accent`
|
|
638
|
-
| `--hub-loading-size`
|
|
639
|
-
| `--hub-loading-thickness`
|
|
640
|
-
| `--hub-loading-speed`
|
|
641
|
-
| `--hub-loading-gap`
|
|
642
|
-
| `--hub-loading-text-color`
|
|
643
|
-
| `--hub-loading-font-size`
|
|
644
|
-
| `--hub-loading-backdrop-bg`
|
|
645
|
-
| `--hub-loading-backdrop-blur` | `2px`
|
|
646
|
-
| `--hub-loading-z-index`
|
|
647
|
-
| `--hub-loading-image-size`
|
|
655
|
+
| Variable | Default | Description |
|
|
656
|
+
| ----------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
657
|
+
| `--hub-loading-accent` | `var(--hub-sys-color-primary, #0d6efd)` | Indicator colour. What the `color` input writes into. |
|
|
658
|
+
| `--hub-loading-size` | `2.5rem` | Indicator box size. What the `size` input maps onto. |
|
|
659
|
+
| `--hub-loading-thickness` | `calc(var(--hub-ref-border-width, 1px) * 3)` | Stroke width of the `spinner` and `ring` indicators. |
|
|
660
|
+
| `--hub-loading-speed` | `0.9s` | Duration of one animation cycle, for the indicators and the image animations. |
|
|
661
|
+
| `--hub-loading-gap` | `var(--hub-sys-gap-2, var(--hub-ref-space-2, 0.5rem))` | Space between indicator, message and projected content. |
|
|
662
|
+
| `--hub-loading-text-color` | `var(--hub-sys-text-primary, var(--hub-ref-color-gray-900, #212529))` | Message colour. |
|
|
663
|
+
| `--hub-loading-font-size` | `var(--hub-ref-font-size-sm, 0.875rem)` | Message font size. |
|
|
664
|
+
| `--hub-loading-backdrop-bg` | `color-mix(in srgb, var(--hub-sys-surface-page, #fff) 72%, transparent)` | Backdrop background in `overlay` / `fullscreen`. Follows the theme's own page surface, so the scrim is a white veil on light themes and a dark one on dark themes. |
|
|
665
|
+
| `--hub-loading-backdrop-blur` | `2px` | Backdrop blur radius. |
|
|
666
|
+
| `--hub-loading-z-index` | `var(--hub-sys-zindex-modal, 1055)` | Stack order of the `fullscreen` layer. |
|
|
667
|
+
| `--hub-loading-image-size` | `var(--hub-loading-size)` | Rendered size of the `image` asset — it follows the indicator size until you say otherwise. |
|
|
648
668
|
|
|
649
669
|
```css
|
|
650
670
|
hub-loading {
|
|
@@ -686,21 +706,21 @@ are literals rather than `--hub-sys-transition-*`: the fill has to arrive roughl
|
|
|
686
706
|
next trickle tick lands, so it is coupled to `trickleSpeed`, and borrowing the application's
|
|
687
707
|
transition scale would let a slow theme leave the bar a tick behind the number it is drawing.
|
|
688
708
|
|
|
689
|
-
| Variable
|
|
690
|
-
|
|
|
691
|
-
| `--hub-loading-bar-accent`
|
|
692
|
-
| `--hub-loading-bar-height`
|
|
693
|
-
| `--hub-loading-bar-track-bg`
|
|
694
|
-
| `--hub-loading-bar-radius`
|
|
695
|
-
| `--hub-loading-bar-speed`
|
|
696
|
-
| `--hub-loading-bar-fade`
|
|
697
|
-
| `--hub-loading-bar-easing`
|
|
698
|
-
| `--hub-loading-bar-glow-color`
|
|
699
|
-
| `--hub-loading-bar-glow-blur`
|
|
700
|
-
| `--hub-loading-bar-glow-spread`
|
|
701
|
-
| `--hub-loading-bar-indeterminate-speed` | `1.6s`
|
|
702
|
-
| `--hub-loading-bar-offset`
|
|
703
|
-
| `--hub-loading-bar-z-index`
|
|
709
|
+
| Variable | Default | Description |
|
|
710
|
+
| --------------------------------------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
711
|
+
| `--hub-loading-bar-accent` | `var(--hub-sys-color-primary, #0d6efd)` | Fill colour. What the `color` input writes into. |
|
|
712
|
+
| `--hub-loading-bar-height` | `3px` | Thickness of the strip. |
|
|
713
|
+
| `--hub-loading-bar-track-bg` | `transparent` | Unfilled track. Transparent so an idle bar draws no permanent line under the navbar. |
|
|
714
|
+
| `--hub-loading-bar-radius` | `0` | Corner radius of the strip and its fill. |
|
|
715
|
+
| `--hub-loading-bar-speed` | `200ms` | How long the fill takes to catch up with a new value. |
|
|
716
|
+
| `--hub-loading-bar-fade` | `300ms` | Fade in and out of the whole strip. |
|
|
717
|
+
| `--hub-loading-bar-easing` | `linear` | Easing of the fill. Linear reads as steady progress rather than as a flourish. |
|
|
718
|
+
| `--hub-loading-bar-glow-color` | `var(--hub-loading-bar-accent)` | Colour of the glow at the leading edge. |
|
|
719
|
+
| `--hub-loading-bar-glow-blur` | `10px` | Blur radius of that glow. |
|
|
720
|
+
| `--hub-loading-bar-glow-spread` | `1px` | Spread radius of that glow. |
|
|
721
|
+
| `--hub-loading-bar-indeterminate-speed` | `1.6s` | Period of one `indeterminate` sweep. Calmed under `prefers-reduced-motion`. |
|
|
722
|
+
| `--hub-loading-bar-offset` | `0px` | Distance from the edge the `overlay` and `fixed` modes attach to — how far under a navbar the bar hangs. |
|
|
723
|
+
| `--hub-loading-bar-z-index` | `var(--hub-sys-zindex-sticky, 1020)` | Stack order of the positioned modes. Chrome level, deliberately below dialogs and toasts. |
|
|
704
724
|
|
|
705
725
|
```css
|
|
706
726
|
hub-loading-bar {
|
|
@@ -717,29 +737,29 @@ contract as `hub-loading-theme()`.
|
|
|
717
737
|
|
|
718
738
|
The internal structure is stable and addressable, for the cases a token cannot reach:
|
|
719
739
|
|
|
720
|
-
| Class
|
|
721
|
-
|
|
|
722
|
-
| `.hub-loading`
|
|
723
|
-
| `.hub-loading--inline` · `--overlay` · `--fullscreen` | Mode modifiers.
|
|
724
|
-
| `.hub-loading--sm` · `--md` · `--lg`
|
|
725
|
-
| `.hub-loading--backdrop`
|
|
726
|
-
| `.hub-loading__indicator`
|
|
727
|
-
| `.hub-loading__dot` · `.hub-loading__bar`
|
|
728
|
-
| `.hub-loading__image`
|
|
729
|
-
| `.hub-loading__message`
|
|
740
|
+
| Class | Element |
|
|
741
|
+
| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
742
|
+
| `.hub-loading` | Host block. |
|
|
743
|
+
| `.hub-loading--inline` · `--overlay` · `--fullscreen` | Mode modifiers. |
|
|
744
|
+
| `.hub-loading--sm` · `--md` · `--lg` | Size modifiers; each retunes the size, thickness and font-size tokens. |
|
|
745
|
+
| `.hub-loading--backdrop` | Present only when the scrim is painted (never in `inline` mode). |
|
|
746
|
+
| `.hub-loading__indicator` | The pure-CSS indicator, plus a `--spinner` / `--dots` / `--bars` / `--pulse` / `--ring` modifier. |
|
|
747
|
+
| `.hub-loading__dot` · `.hub-loading__bar` | The individual parts of the `dots` and `bars` indicators. |
|
|
748
|
+
| `.hub-loading__image` | The `image` asset, plus `--spin` / `--pulse` when animated. |
|
|
749
|
+
| `.hub-loading__message` | The message text. |
|
|
730
750
|
|
|
731
751
|
The bar has its own set, and it is worth knowing because most of it is state you can style
|
|
732
752
|
against rather than structure you have to reach into:
|
|
733
753
|
|
|
734
|
-
| Class
|
|
735
|
-
|
|
|
736
|
-
| `.hub-loading-bar`
|
|
737
|
-
| `.hub-loading-bar--inline` · `--overlay` · `--fixed` | Mode modifiers.
|
|
738
|
-
| `.hub-loading-bar--top` · `--bottom`
|
|
739
|
-
| `.hub-loading-bar--visible`
|
|
740
|
-
| `.hub-loading-bar--indeterminate`
|
|
741
|
-
| `.hub-loading-bar--glow`
|
|
742
|
-
| `.hub-loading-bar__indicator`
|
|
754
|
+
| Class | Element |
|
|
755
|
+
| ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
|
756
|
+
| `.hub-loading-bar` | Host block. |
|
|
757
|
+
| `.hub-loading-bar--inline` · `--overlay` · `--fixed` | Mode modifiers. |
|
|
758
|
+
| `.hub-loading-bar--top` · `--bottom` | Placement modifiers; emitted only by the two positioned modes, so they can never reach an inline bar. |
|
|
759
|
+
| `.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. |
|
|
760
|
+
| `.hub-loading-bar--indeterminate` | The sweep is running instead of a fill. |
|
|
761
|
+
| `.hub-loading-bar--glow` | The leading-edge glow is on — the shipped default, unless `[glow]="false"` or a re-based `provideHubLoadingBar()` turns it off. |
|
|
762
|
+
| `.hub-loading-bar__indicator` | The fill itself; its `::after` paints the glow. |
|
|
743
763
|
|
|
744
764
|
### Right-to-left
|
|
745
765
|
|
|
@@ -800,9 +820,9 @@ mirrors on its own.
|
|
|
800
820
|
|
|
801
821
|
```json
|
|
802
822
|
{
|
|
803
|
-
"@angular/common": ">=17.
|
|
804
|
-
"@angular/core": ">=17.
|
|
805
|
-
"@angular/router": ">=17.
|
|
823
|
+
"@angular/common": ">=17.3.0",
|
|
824
|
+
"@angular/core": ">=17.3.0",
|
|
825
|
+
"@angular/router": ">=17.3.0",
|
|
806
826
|
"ng-hub-ui-utils": ">=22.8.0",
|
|
807
827
|
"rxjs": ">=7.5.0"
|
|
808
828
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
|
|
1
2
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, makeEnvironmentProviders, inject, input, booleanAttribute, computed, ChangeDetectionStrategy, Component, ApplicationRef,
|
|
3
|
+
import { InjectionToken, makeEnvironmentProviders, inject, input, booleanAttribute, computed, ElementRef, PLATFORM_ID, effect, DestroyRef, ChangeDetectionStrategy, Component, ApplicationRef, signal, untracked, createComponent, Injectable, NgZone, provideAppInitializer } from '@angular/core';
|
|
3
4
|
import { resolveHubAccent } from 'ng-hub-ui-utils';
|
|
4
|
-
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
|
|
5
5
|
import { HttpContextToken, HttpContext } from '@angular/common/http';
|
|
6
6
|
import { finalize } from 'rxjs';
|
|
7
7
|
import { NavigationEnd, NavigationCancel, NavigationError, NavigationSkipped, Router, NavigationStart } from '@angular/router';
|
|
@@ -60,6 +60,9 @@ function provideHubLoading(config = {}) {
|
|
|
60
60
|
* out-specify anything. The overlay `HubLoadingService` mounts on `document.body` is a
|
|
61
61
|
* regular instance of this component, so it carries the same stylesheet with it.
|
|
62
62
|
*
|
|
63
|
+
* A `fullscreen` indicator moves to `<body>` for the same reason the service mounts there —
|
|
64
|
+
* see {@link appendTo}.
|
|
65
|
+
*
|
|
63
66
|
* @example
|
|
64
67
|
* ```html
|
|
65
68
|
* <hub-loading variant="dots" message="Loading orders…" />
|
|
@@ -74,7 +77,8 @@ class HubLoadingComponent {
|
|
|
74
77
|
config = inject(HUB_LOADING_CONFIG);
|
|
75
78
|
/**
|
|
76
79
|
* Placement of the indicator. `overlay` needs a positioned ancestor to cover;
|
|
77
|
-
* `fullscreen` is fixed to the viewport
|
|
80
|
+
* `fullscreen` is fixed to the viewport, layered at `--hub-loading-z-index`, and moved to
|
|
81
|
+
* {@link appendTo} so neither of those is decided by an ancestor.
|
|
78
82
|
*/
|
|
79
83
|
mode = input('inline', /* @ts-ignore */
|
|
80
84
|
...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
|
|
@@ -105,6 +109,25 @@ class HubLoadingComponent {
|
|
|
105
109
|
/** Accessible label announced by the host's `role="status"` live region. */
|
|
106
110
|
ariaLabel = input(this.config.ariaLabel, /* @ts-ignore */
|
|
107
111
|
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
112
|
+
/**
|
|
113
|
+
* CSS selector of the element a `fullscreen` indicator is re-parented to; `null` leaves it
|
|
114
|
+
* where the template declares it.
|
|
115
|
+
*
|
|
116
|
+
* `position: fixed` measures from the viewport only while no ancestor applies layout
|
|
117
|
+
* containment, a transform or a filter, and it paints over the page only while no ancestor
|
|
118
|
+
* opens a stacking context. A shell cannot promise either — `<hub-side-panel-container>`
|
|
119
|
+
* opens one on purpose, and any card with a `transform` breaks the first — so an indicator
|
|
120
|
+
* declared deep in a page covered its own corner of it rather than the window. Leaving the
|
|
121
|
+
* subtree is the only fix that does not depend on what every ancestor happens to declare, and
|
|
122
|
+
* it is what the family already does with anything that has to float (a select panel, the
|
|
123
|
+
* service's own overlay). `inline` and `overlay` are never moved: they exist to sit where the
|
|
124
|
+
* consumer put them.
|
|
125
|
+
*
|
|
126
|
+
* A selector that matches nothing leaves the indicator in place rather than guessing at
|
|
127
|
+
* another parent.
|
|
128
|
+
*/
|
|
129
|
+
appendTo = input('body', /* @ts-ignore */
|
|
130
|
+
...(ngDevMode ? [{ debugName: "appendTo" }] : /* istanbul ignore next */ []));
|
|
108
131
|
/** Mode and size modifiers; kept as one binding so a size change cannot drop the mode. */
|
|
109
132
|
_modifierClasses = computed(() => `hub-loading--${this.mode()} hub-loading--${this.size()}`, /* @ts-ignore */
|
|
110
133
|
...(ngDevMode ? [{ debugName: "_modifierClasses" }] : /* istanbul ignore next */ []));
|
|
@@ -123,8 +146,48 @@ class HubLoadingComponent {
|
|
|
123
146
|
/** Motion modifier for the branding image; `none` adds no class at all. */
|
|
124
147
|
_imageClasses = computed(() => this.imageAnimation() === 'none' ? '' : `hub-loading__image--${this.imageAnimation()}`, /* @ts-ignore */
|
|
125
148
|
...(ngDevMode ? [{ debugName: "_imageClasses" }] : /* istanbul ignore next */ []));
|
|
149
|
+
constructor() {
|
|
150
|
+
const host = inject(ElementRef).nativeElement;
|
|
151
|
+
const document = inject(DOCUMENT);
|
|
152
|
+
const isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
|
|
153
|
+
/** Where the template put the node, remembered on the first move so it can be put back. */
|
|
154
|
+
let home = null;
|
|
155
|
+
effect(() => {
|
|
156
|
+
const selector = this.mode() === 'fullscreen' ? this.appendTo() : null;
|
|
157
|
+
// The server renders the indicator where it is written; hydration finds it there and
|
|
158
|
+
// the move happens once on the client, after the first change detection.
|
|
159
|
+
if (!isBrowser) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const target = selector ? document.querySelector(selector) : null;
|
|
163
|
+
if (!target) {
|
|
164
|
+
if (home) {
|
|
165
|
+
// The anchor may be gone if the surrounding view was rebuilt, and inserting
|
|
166
|
+
// before a node that moved throws; appending to the old parent still lands the
|
|
167
|
+
// indicator back in the block it came from.
|
|
168
|
+
home.parent.insertBefore(host, home.before?.parentNode === home.parent ? home.before : null);
|
|
169
|
+
home = null;
|
|
170
|
+
}
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (target === host.parentNode) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (host.parentNode) {
|
|
177
|
+
home ??= { parent: host.parentNode, before: host.nextSibling };
|
|
178
|
+
}
|
|
179
|
+
target.appendChild(host);
|
|
180
|
+
});
|
|
181
|
+
inject(DestroyRef).onDestroy(() => {
|
|
182
|
+
// Angular removes the host node it created, but this one no longer hangs from the view
|
|
183
|
+
// being torn down, so nothing else would take it off the page.
|
|
184
|
+
if (home) {
|
|
185
|
+
host.remove();
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
}
|
|
126
189
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: HubLoadingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
127
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: HubLoadingComponent, isStandalone: true, selector: "hub-loading", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, image: { classPropertyName: "image", publicName: "image", isSignal: true, isRequired: false, transformFunction: null }, imageAnimation: { classPropertyName: "imageAnimation", publicName: "imageAnimation", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, backdrop: { classPropertyName: "backdrop", publicName: "backdrop", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "status", "aria-live": "polite", "aria-busy": "true" }, properties: { "class": "_modifierClasses()", "class.hub-loading--backdrop": "_showsBackdrop()", "attr.aria-label": "ariaLabel()", "style.--hub-loading-accent": "_accent()" }, classAttribute: "hub-loading" }, ngImport: i0, template: "@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", styles: [":where(:host){--hub-loading-accent: var(--hub-sys-color-primary, #0d6efd);--hub-loading-size: 2.5rem;--hub-loading-thickness: calc(var(--hub-ref-border-width, 1px) * 3);--hub-loading-speed: .9s;--hub-loading-gap: var(--hub-sys-gap-2, var(--hub-ref-space-2, .5rem));--hub-loading-text-color: var(--hub-sys-text-primary, var(--hub-ref-color-gray-900, #212529));--hub-loading-font-size: var(--hub-ref-font-size-sm, .875rem);--hub-loading-backdrop-bg: color-mix(in srgb, var(--hub-sys-surface-page, #ffffff) 72%, transparent);--hub-loading-backdrop-blur: 2px;--hub-loading-z-index: var(--hub-sys-zindex-modal, 1055);--hub-loading-image-size: var(--hub-loading-size)}:host{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--hub-loading-gap);color:var(--hub-loading-text-color);font-size:var(--hub-loading-font-size)}:host(.hub-loading--overlay){position:absolute;inset:0}:host(.hub-loading--fullscreen){position:fixed;inset:0;z-index:var(--hub-loading-z-index)}:host(.hub-loading--backdrop){background:var(--hub-loading-backdrop-bg);-webkit-backdrop-filter:blur(var(--hub-loading-backdrop-blur));backdrop-filter:blur(var(--hub-loading-backdrop-blur))}:host(.hub-loading--sm){--hub-loading-size: 1.5rem;--hub-loading-thickness: calc(var(--hub-ref-border-width, 1px) * 2);--hub-loading-font-size: var(--hub-ref-font-size-xs, .75rem)}:host(.hub-loading--lg){--hub-loading-size: 4rem;--hub-loading-thickness: calc(var(--hub-ref-border-width, 1px) * 4);--hub-loading-font-size: var(--hub-ref-font-size-base, 1rem)}.hub-loading__indicator{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;inline-size:var(--hub-loading-size);block-size:var(--hub-loading-size);color:var(--hub-loading-accent)}.hub-loading__indicator--spinner{border:var(--hub-loading-thickness) solid color-mix(in srgb,var(--hub-loading-accent) 20%,transparent);border-block-start-color:var(--hub-loading-accent);border-radius:50%;animation:hub-loading-spin var(--hub-loading-speed) linear infinite}.hub-loading__indicator--ring{background:conic-gradient(from 0deg,transparent 0%,var(--hub-loading-accent) 100%);border-radius:50%;-webkit-mask:radial-gradient(farthest-side,transparent calc(100% - var(--hub-loading-thickness)),#000 calc(100% - var(--hub-loading-thickness)));mask:radial-gradient(farthest-side,transparent calc(100% - var(--hub-loading-thickness)),#000 calc(100% - var(--hub-loading-thickness)));animation:hub-loading-spin var(--hub-loading-speed) linear infinite}.hub-loading__indicator--dots{inline-size:auto;gap:calc(var(--hub-loading-size) / 5)}.hub-loading__dot{flex:0 0 auto;inline-size:calc(var(--hub-loading-size) / 4);block-size:calc(var(--hub-loading-size) / 4);background:var(--hub-loading-accent);border-radius:50%;animation:hub-loading-dot var(--hub-loading-speed) ease-in-out infinite}.hub-loading__dot:nth-child(2){animation-delay:calc(var(--hub-loading-speed) / 6)}.hub-loading__dot:nth-child(3){animation-delay:calc(var(--hub-loading-speed) / 3)}.hub-loading__indicator--bars{gap:calc(var(--hub-loading-size) / 8)}.hub-loading__bar{flex:0 0 auto;inline-size:calc(var(--hub-loading-size) / 8);block-size:100%;background:var(--hub-loading-accent);border-radius:var(--hub-sys-radius-pill, 50rem);transform-origin:center;animation:hub-loading-bar var(--hub-loading-speed) ease-in-out infinite}.hub-loading__bar:nth-child(2){animation-delay:calc(var(--hub-loading-speed) / 8)}.hub-loading__bar:nth-child(3){animation-delay:calc(var(--hub-loading-speed) / 4)}.hub-loading__bar:nth-child(4){animation-delay:calc(var(--hub-loading-speed) * 3 / 8)}.hub-loading__indicator--pulse{background:var(--hub-loading-accent);border-radius:50%;animation:hub-loading-pulse calc(var(--hub-loading-speed) * 1.4) ease-in-out infinite}.hub-loading__image{inline-size:var(--hub-loading-image-size);block-size:var(--hub-loading-image-size);object-fit:contain}.hub-loading__image--spin{animation:hub-loading-spin calc(var(--hub-loading-speed) * 1.6) linear infinite}.hub-loading__image--pulse{animation:hub-loading-pulse calc(var(--hub-loading-speed) * 1.6) ease-in-out infinite}.hub-loading__message{margin:0;color:var(--hub-loading-text-color);font-size:var(--hub-loading-font-size);text-align:center}@media(prefers-reduced-motion:reduce){:host{--hub-loading-speed: 2.4s}.hub-loading__indicator--spinner,.hub-loading__indicator--ring,.hub-loading__indicator--pulse,.hub-loading__dot,.hub-loading__bar,.hub-loading__image--spin,.hub-loading__image--pulse{animation-name:hub-loading-fade;animation-duration:var(--hub-loading-speed);animation-timing-function:ease-in-out}}@keyframes hub-loading-spin{to{transform:rotate(360deg)}}@keyframes hub-loading-dot{0%,80%,to{opacity:.3;transform:scale(.7)}40%{opacity:1;transform:scale(1)}}@keyframes hub-loading-bar{0%,to{transform:scaleY(.35)}50%{transform:scaleY(1)}}@keyframes hub-loading-pulse{0%,to{opacity:.35;transform:scale(.75)}50%{opacity:1;transform:scale(1)}}@keyframes hub-loading-fade{0%,to{opacity:.35}50%{opacity:1}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
190
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: HubLoadingComponent, isStandalone: true, selector: "hub-loading", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, image: { classPropertyName: "image", publicName: "image", isSignal: true, isRequired: false, transformFunction: null }, imageAnimation: { classPropertyName: "imageAnimation", publicName: "imageAnimation", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, backdrop: { classPropertyName: "backdrop", publicName: "backdrop", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, appendTo: { classPropertyName: "appendTo", publicName: "appendTo", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "status", "aria-live": "polite", "aria-busy": "true" }, properties: { "class": "_modifierClasses()", "class.hub-loading--backdrop": "_showsBackdrop()", "attr.aria-label": "ariaLabel()", "style.--hub-loading-accent": "_accent()" }, classAttribute: "hub-loading" }, ngImport: i0, template: "@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", styles: [":where(:host){--hub-loading-accent: var(--hub-sys-color-primary, #0d6efd);--hub-loading-size: 2.5rem;--hub-loading-thickness: calc(var(--hub-ref-border-width, 1px) * 3);--hub-loading-speed: .9s;--hub-loading-gap: var(--hub-sys-gap-2, var(--hub-ref-space-2, .5rem));--hub-loading-text-color: var(--hub-sys-text-primary, var(--hub-ref-color-gray-900, #212529));--hub-loading-font-size: var(--hub-ref-font-size-sm, .875rem);--hub-loading-backdrop-bg: color-mix(in srgb, var(--hub-sys-surface-page, #ffffff) 72%, transparent);--hub-loading-backdrop-blur: 2px;--hub-loading-z-index: var(--hub-sys-zindex-modal, 1055);--hub-loading-image-size: var(--hub-loading-size)}:host{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--hub-loading-gap);color:var(--hub-loading-text-color);font-size:var(--hub-loading-font-size)}:host(.hub-loading--overlay){position:absolute;inset:0}:host(.hub-loading--fullscreen){position:fixed;inset:0;z-index:var(--hub-loading-z-index)}:host(.hub-loading--backdrop){background:var(--hub-loading-backdrop-bg);-webkit-backdrop-filter:blur(var(--hub-loading-backdrop-blur));backdrop-filter:blur(var(--hub-loading-backdrop-blur))}:host(.hub-loading--sm){--hub-loading-size: 1.5rem;--hub-loading-thickness: calc(var(--hub-ref-border-width, 1px) * 2);--hub-loading-font-size: var(--hub-ref-font-size-xs, .75rem)}:host(.hub-loading--lg){--hub-loading-size: 4rem;--hub-loading-thickness: calc(var(--hub-ref-border-width, 1px) * 4);--hub-loading-font-size: var(--hub-ref-font-size-base, 1rem)}.hub-loading__indicator{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;inline-size:var(--hub-loading-size);block-size:var(--hub-loading-size);color:var(--hub-loading-accent)}.hub-loading__indicator--spinner{border:var(--hub-loading-thickness) solid color-mix(in srgb,var(--hub-loading-accent) 20%,transparent);border-block-start-color:var(--hub-loading-accent);border-radius:50%;animation:hub-loading-spin var(--hub-loading-speed) linear infinite}.hub-loading__indicator--ring{background:conic-gradient(from 0deg,transparent 0%,var(--hub-loading-accent) 100%);border-radius:50%;-webkit-mask:radial-gradient(farthest-side,transparent calc(100% - var(--hub-loading-thickness)),#000 calc(100% - var(--hub-loading-thickness)));mask:radial-gradient(farthest-side,transparent calc(100% - var(--hub-loading-thickness)),#000 calc(100% - var(--hub-loading-thickness)));animation:hub-loading-spin var(--hub-loading-speed) linear infinite}.hub-loading__indicator--dots{inline-size:auto;gap:calc(var(--hub-loading-size) / 5)}.hub-loading__dot{flex:0 0 auto;inline-size:calc(var(--hub-loading-size) / 4);block-size:calc(var(--hub-loading-size) / 4);background:var(--hub-loading-accent);border-radius:50%;animation:hub-loading-dot var(--hub-loading-speed) ease-in-out infinite}.hub-loading__dot:nth-child(2){animation-delay:calc(var(--hub-loading-speed) / 6)}.hub-loading__dot:nth-child(3){animation-delay:calc(var(--hub-loading-speed) / 3)}.hub-loading__indicator--bars{gap:calc(var(--hub-loading-size) / 8)}.hub-loading__bar{flex:0 0 auto;inline-size:calc(var(--hub-loading-size) / 8);block-size:100%;background:var(--hub-loading-accent);border-radius:var(--hub-sys-radius-pill, 50rem);transform-origin:center;animation:hub-loading-bar var(--hub-loading-speed) ease-in-out infinite}.hub-loading__bar:nth-child(2){animation-delay:calc(var(--hub-loading-speed) / 8)}.hub-loading__bar:nth-child(3){animation-delay:calc(var(--hub-loading-speed) / 4)}.hub-loading__bar:nth-child(4){animation-delay:calc(var(--hub-loading-speed) * 3 / 8)}.hub-loading__indicator--pulse{background:var(--hub-loading-accent);border-radius:50%;animation:hub-loading-pulse calc(var(--hub-loading-speed) * 1.4) ease-in-out infinite}.hub-loading__image{inline-size:var(--hub-loading-image-size);block-size:var(--hub-loading-image-size);object-fit:contain}.hub-loading__image--spin{animation:hub-loading-spin calc(var(--hub-loading-speed) * 1.6) linear infinite}.hub-loading__image--pulse{animation:hub-loading-pulse calc(var(--hub-loading-speed) * 1.6) ease-in-out infinite}.hub-loading__message{margin:0;color:var(--hub-loading-text-color);font-size:var(--hub-loading-font-size);text-align:center}@media(prefers-reduced-motion:reduce){:host{--hub-loading-speed: 2.4s}.hub-loading__indicator--spinner,.hub-loading__indicator--ring,.hub-loading__indicator--pulse,.hub-loading__dot,.hub-loading__bar,.hub-loading__image--spin,.hub-loading__image--pulse{animation-name:hub-loading-fade;animation-duration:var(--hub-loading-speed);animation-timing-function:ease-in-out}}@keyframes hub-loading-spin{to{transform:rotate(360deg)}}@keyframes hub-loading-dot{0%,80%,to{opacity:.3;transform:scale(.7)}40%{opacity:1;transform:scale(1)}}@keyframes hub-loading-bar{0%,to{transform:scaleY(.35)}50%{transform:scaleY(1)}}@keyframes hub-loading-pulse{0%,to{opacity:.35;transform:scale(.75)}50%{opacity:1;transform:scale(1)}}@keyframes hub-loading-fade{0%,to{opacity:.35}50%{opacity:1}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
128
191
|
}
|
|
129
192
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: HubLoadingComponent, decorators: [{
|
|
130
193
|
type: Component,
|
|
@@ -138,7 +201,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
138
201
|
'[attr.aria-label]': 'ariaLabel()',
|
|
139
202
|
'[style.--hub-loading-accent]': '_accent()'
|
|
140
203
|
}, template: "@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", styles: [":where(:host){--hub-loading-accent: var(--hub-sys-color-primary, #0d6efd);--hub-loading-size: 2.5rem;--hub-loading-thickness: calc(var(--hub-ref-border-width, 1px) * 3);--hub-loading-speed: .9s;--hub-loading-gap: var(--hub-sys-gap-2, var(--hub-ref-space-2, .5rem));--hub-loading-text-color: var(--hub-sys-text-primary, var(--hub-ref-color-gray-900, #212529));--hub-loading-font-size: var(--hub-ref-font-size-sm, .875rem);--hub-loading-backdrop-bg: color-mix(in srgb, var(--hub-sys-surface-page, #ffffff) 72%, transparent);--hub-loading-backdrop-blur: 2px;--hub-loading-z-index: var(--hub-sys-zindex-modal, 1055);--hub-loading-image-size: var(--hub-loading-size)}:host{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--hub-loading-gap);color:var(--hub-loading-text-color);font-size:var(--hub-loading-font-size)}:host(.hub-loading--overlay){position:absolute;inset:0}:host(.hub-loading--fullscreen){position:fixed;inset:0;z-index:var(--hub-loading-z-index)}:host(.hub-loading--backdrop){background:var(--hub-loading-backdrop-bg);-webkit-backdrop-filter:blur(var(--hub-loading-backdrop-blur));backdrop-filter:blur(var(--hub-loading-backdrop-blur))}:host(.hub-loading--sm){--hub-loading-size: 1.5rem;--hub-loading-thickness: calc(var(--hub-ref-border-width, 1px) * 2);--hub-loading-font-size: var(--hub-ref-font-size-xs, .75rem)}:host(.hub-loading--lg){--hub-loading-size: 4rem;--hub-loading-thickness: calc(var(--hub-ref-border-width, 1px) * 4);--hub-loading-font-size: var(--hub-ref-font-size-base, 1rem)}.hub-loading__indicator{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;inline-size:var(--hub-loading-size);block-size:var(--hub-loading-size);color:var(--hub-loading-accent)}.hub-loading__indicator--spinner{border:var(--hub-loading-thickness) solid color-mix(in srgb,var(--hub-loading-accent) 20%,transparent);border-block-start-color:var(--hub-loading-accent);border-radius:50%;animation:hub-loading-spin var(--hub-loading-speed) linear infinite}.hub-loading__indicator--ring{background:conic-gradient(from 0deg,transparent 0%,var(--hub-loading-accent) 100%);border-radius:50%;-webkit-mask:radial-gradient(farthest-side,transparent calc(100% - var(--hub-loading-thickness)),#000 calc(100% - var(--hub-loading-thickness)));mask:radial-gradient(farthest-side,transparent calc(100% - var(--hub-loading-thickness)),#000 calc(100% - var(--hub-loading-thickness)));animation:hub-loading-spin var(--hub-loading-speed) linear infinite}.hub-loading__indicator--dots{inline-size:auto;gap:calc(var(--hub-loading-size) / 5)}.hub-loading__dot{flex:0 0 auto;inline-size:calc(var(--hub-loading-size) / 4);block-size:calc(var(--hub-loading-size) / 4);background:var(--hub-loading-accent);border-radius:50%;animation:hub-loading-dot var(--hub-loading-speed) ease-in-out infinite}.hub-loading__dot:nth-child(2){animation-delay:calc(var(--hub-loading-speed) / 6)}.hub-loading__dot:nth-child(3){animation-delay:calc(var(--hub-loading-speed) / 3)}.hub-loading__indicator--bars{gap:calc(var(--hub-loading-size) / 8)}.hub-loading__bar{flex:0 0 auto;inline-size:calc(var(--hub-loading-size) / 8);block-size:100%;background:var(--hub-loading-accent);border-radius:var(--hub-sys-radius-pill, 50rem);transform-origin:center;animation:hub-loading-bar var(--hub-loading-speed) ease-in-out infinite}.hub-loading__bar:nth-child(2){animation-delay:calc(var(--hub-loading-speed) / 8)}.hub-loading__bar:nth-child(3){animation-delay:calc(var(--hub-loading-speed) / 4)}.hub-loading__bar:nth-child(4){animation-delay:calc(var(--hub-loading-speed) * 3 / 8)}.hub-loading__indicator--pulse{background:var(--hub-loading-accent);border-radius:50%;animation:hub-loading-pulse calc(var(--hub-loading-speed) * 1.4) ease-in-out infinite}.hub-loading__image{inline-size:var(--hub-loading-image-size);block-size:var(--hub-loading-image-size);object-fit:contain}.hub-loading__image--spin{animation:hub-loading-spin calc(var(--hub-loading-speed) * 1.6) linear infinite}.hub-loading__image--pulse{animation:hub-loading-pulse calc(var(--hub-loading-speed) * 1.6) ease-in-out infinite}.hub-loading__message{margin:0;color:var(--hub-loading-text-color);font-size:var(--hub-loading-font-size);text-align:center}@media(prefers-reduced-motion:reduce){:host{--hub-loading-speed: 2.4s}.hub-loading__indicator--spinner,.hub-loading__indicator--ring,.hub-loading__indicator--pulse,.hub-loading__dot,.hub-loading__bar,.hub-loading__image--spin,.hub-loading__image--pulse{animation-name:hub-loading-fade;animation-duration:var(--hub-loading-speed);animation-timing-function:ease-in-out}}@keyframes hub-loading-spin{to{transform:rotate(360deg)}}@keyframes hub-loading-dot{0%,80%,to{opacity:.3;transform:scale(.7)}40%{opacity:1;transform:scale(1)}}@keyframes hub-loading-bar{0%,to{transform:scaleY(.35)}50%{transform:scaleY(1)}}@keyframes hub-loading-pulse{0%,to{opacity:.35;transform:scale(.75)}50%{opacity:1;transform:scale(1)}}@keyframes hub-loading-fade{0%,to{opacity:.35}50%{opacity:1}}\n"] }]
|
|
141
|
-
}], propDecorators: { mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], image: [{ type: i0.Input, args: [{ isSignal: true, alias: "image", required: false }] }], imageAnimation: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageAnimation", required: false }] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], backdrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "backdrop", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
|
|
204
|
+
}], ctorParameters: () => [], propDecorators: { mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], image: [{ type: i0.Input, args: [{ isSignal: true, alias: "image", required: false }] }], imageAnimation: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageAnimation", required: false }] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], backdrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "backdrop", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], appendTo: [{ type: i0.Input, args: [{ isSignal: true, alias: "appendTo", required: false }] }] } });
|
|
142
205
|
|
|
143
206
|
/**
|
|
144
207
|
* Drives a single application-wide fullscreen loading overlay.
|
|
@@ -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 { booleanAttribute, ChangeDetectionStrategy, Component, computed, inject, input } 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 * Every `--hub-loading-*` token is declared on the host at zero specificity, so a\n * consumer retheming the indicator from a global stylesheet wins without having to\n * out-specify anything. The overlay `HubLoadingService` mounts on `document.body` is a\n * regular instance of this component, so it carries the same stylesheet with it.\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\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 { booleanAttribute, ChangeDetectionStrategy, Component, computed, inject, input } 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 * Every `--hub-loading-bar-*` token is declared on the host at zero specificity, so a\n * consumer retheming the bar from a global stylesheet wins without out-specifying anything.\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\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 { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport {\n\tbooleanAttribute,\n\tChangeDetectionStrategy,\n\tComponent,\n\tcomputed,\n\tDestroyRef,\n\teffect,\n\tElementRef,\n\tinject,\n\tinput,\n\tPLATFORM_ID\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 * Every `--hub-loading-*` token is declared on the host at zero specificity, so a\n * consumer retheming the indicator from a global stylesheet wins without having to\n * out-specify anything. The overlay `HubLoadingService` mounts on `document.body` is a\n * regular instance of this component, so it carries the same stylesheet with it.\n *\n * A `fullscreen` indicator moves to `<body>` for the same reason the service mounts there —\n * see {@link appendTo}.\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\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, layered at `--hub-loading-z-index`, and moved to\n\t * {@link appendTo} so neither of those is decided by an ancestor.\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/**\n\t * CSS selector of the element a `fullscreen` indicator is re-parented to; `null` leaves it\n\t * where the template declares it.\n\t *\n\t * `position: fixed` measures from the viewport only while no ancestor applies layout\n\t * containment, a transform or a filter, and it paints over the page only while no ancestor\n\t * opens a stacking context. A shell cannot promise either — `<hub-side-panel-container>`\n\t * opens one on purpose, and any card with a `transform` breaks the first — so an indicator\n\t * declared deep in a page covered its own corner of it rather than the window. Leaving the\n\t * subtree is the only fix that does not depend on what every ancestor happens to declare, and\n\t * it is what the family already does with anything that has to float (a select panel, the\n\t * service's own overlay). `inline` and `overlay` are never moved: they exist to sit where the\n\t * consumer put them.\n\t *\n\t * A selector that matches nothing leaves the indicator in place rather than guessing at\n\t * another parent.\n\t */\n\treadonly appendTo = input<string | null>('body');\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\tconstructor() {\n\t\tconst host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n\t\tconst document = inject(DOCUMENT);\n\t\tconst isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n\t\t/** Where the template put the node, remembered on the first move so it can be put back. */\n\t\tlet home: { parent: Node; before: Node | null } | null = null;\n\n\t\teffect(() => {\n\t\t\tconst selector = this.mode() === 'fullscreen' ? this.appendTo() : null;\n\n\t\t\t// The server renders the indicator where it is written; hydration finds it there and\n\t\t\t// the move happens once on the client, after the first change detection.\n\t\t\tif (!isBrowser) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst target = selector ? document.querySelector(selector) : null;\n\n\t\t\tif (!target) {\n\t\t\t\tif (home) {\n\t\t\t\t\t// The anchor may be gone if the surrounding view was rebuilt, and inserting\n\t\t\t\t\t// before a node that moved throws; appending to the old parent still lands the\n\t\t\t\t\t// indicator back in the block it came from.\n\t\t\t\t\thome.parent.insertBefore(host, home.before?.parentNode === home.parent ? home.before : null);\n\t\t\t\t\thome = null;\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (target === host.parentNode) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (host.parentNode) {\n\t\t\t\thome ??= { parent: host.parentNode, before: host.nextSibling };\n\t\t\t}\n\t\t\ttarget.appendChild(host);\n\t\t});\n\n\t\tinject(DestroyRef).onDestroy(() => {\n\t\t\t// Angular removes the host node it created, but this one no longer hangs from the view\n\t\t\t// being torn down, so nothing else would take it off the page.\n\t\t\tif (home) {\n\t\t\t\thost.remove();\n\t\t\t}\n\t\t});\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 { booleanAttribute, ChangeDetectionStrategy, Component, computed, inject, input } 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 * Every `--hub-loading-bar-*` token is declared on the host at zero specificity, so a\n * consumer retheming the bar from a global stylesheet wins without out-specifying anything.\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\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":";;;;;;;;AAGA;;;;;AAKG;AACI,MAAM,0BAA0B,GAAqB;AAC3D,IAAA,OAAO,EAAE,IAAI;AACb,IAAA,OAAO,EAAE,SAAS;AAClB,IAAA,KAAK,EAAE,IAAI;AACX,IAAA,cAAc,EAAE,MAAM;AACtB,IAAA,IAAI,EAAE,IAAI;AACV,IAAA,KAAK,EAAE,IAAI;AACX,IAAA,QAAQ,EAAE,IAAI;AACd,IAAA,SAAS,EAAE;;AAGZ;;;;;AAKG;MACU,kBAAkB,GAAG,IAAI,cAAc,CAAmB,oBAAoB,EAAE;AAC5F,IAAA,UAAU,EAAE,MAAM;AAClB,IAAA,OAAO,EAAE,MAAM;AACf,CAAA;AAED;;;;;;AAMG;AACG,SAAU,iBAAiB,CAAC,MAAA,GAAoC,EAAE,EAAA;AACvE,IAAA,OAAO,wBAAwB,CAAC;AAC/B,QAAA;AACC,YAAA,OAAO,EAAE,kBAAkB;AAC3B,YAAA,QAAQ,EAAE,EAAE,GAAG,0BAA0B,EAAE,GAAG,MAAM;AACpD;AACD,KAAA,CAAC;AACH;;AC5BA;;;;;;;;;;;;;;;;;;;;;;;AAuBG;MAkBU,mBAAmB,CAAA;;AAEd,IAAA,MAAM,GAAG,MAAM,CAAC,kBAAkB,CAAC;AAEpD;;;;AAIG;IACM,IAAI,GAAG,KAAK,CAAiB,QAAQ;6EAAC;;AAGtC,IAAA,OAAO,GAAG,KAAK,CAAoB,IAAI,CAAC,MAAM,CAAC,OAAO;gFAAC;;AAGvD,IAAA,KAAK,GAAG,KAAK,CAAgB,IAAI,CAAC,MAAM,CAAC,KAAK;8EAAC;;AAG/C,IAAA,cAAc,GAAG,KAAK,CAA2B,IAAI,CAAC,MAAM,CAAC,cAAc;uFAAC;;AAG5E,IAAA,OAAO,GAAG,KAAK,CAAgB,IAAI,CAAC,MAAM,CAAC,OAAO;gFAAC;;AAGnD,IAAA,IAAI,GAAG,KAAK,CAAiB,IAAI,CAAC,MAAM,CAAC,IAAI;6EAAC;AAEvD;;;;AAIG;AACM,IAAA,KAAK,GAAG,KAAK,CAAgB,IAAI,CAAC,MAAM,CAAC,KAAK;8EAAC;;AAG/C,IAAA,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAA,EAAA,IAAA,SAAA,GAAA,EAAA,SAAA,EAAA,UAAA,EAAA,8BAAA,EAAA,CAAA,EAAI,SAAS,EAAE,gBAAgB,GAAG;;AAGvE,IAAA,SAAS,GAAG,KAAK,CAAS,IAAI,CAAC,MAAM,CAAC,SAAS;kFAAC;AAEzD;;;;;;;;;;;;;;;;AAgBG;IACM,QAAQ,GAAG,KAAK,CAAgB,MAAM;iFAAC;;AAG7B,IAAA,gBAAgB,GAAG,QAAQ,CAAC,MAAM,CAAA,aAAA,EAAgB,IAAI,CAAC,IAAI,EAAE,CAAA,cAAA,EAAiB,IAAI,CAAC,IAAI,EAAE,CAAA,CAAE;yFAAC;AAE/G;;;AAGG;AACgB,IAAA,cAAc,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,QAAQ;uFAAC;AAE/F;;;AAGG;AACgB,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAM,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;gFAAC;;IAGxD,aAAa,GAAG,QAAQ,CAAC,MAC3C,IAAI,CAAC,cAAc,EAAE,KAAK,MAAM,GAAG,EAAE,GAAG,uBAAuB,IAAI,CAAC,cAAc,EAAE,CAAA,CAAE;sFACtF;AAED,IAAA,WAAA,GAAA;QACC,MAAM,IAAI,GAAG,MAAM,CAA0B,UAAU,CAAC,CAAC,aAAa;AACtE,QAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QACjC,MAAM,SAAS,GAAG,iBAAiB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;;QAGxD,IAAI,IAAI,GAAiD,IAAI;QAE7D,MAAM,CAAC,MAAK;AACX,YAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,YAAY,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI;;;YAItE,IAAI,CAAC,SAAS,EAAE;gBACf;YACD;AAEA,YAAA,MAAM,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,GAAG,IAAI;YAEjE,IAAI,CAAC,MAAM,EAAE;gBACZ,IAAI,IAAI,EAAE;;;;oBAIT,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;oBAC5F,IAAI,GAAG,IAAI;gBACZ;gBACA;YACD;AAEA,YAAA,IAAI,MAAM,KAAK,IAAI,CAAC,UAAU,EAAE;gBAC/B;YACD;AAEA,YAAA,IAAI,IAAI,CAAC,UAAU,EAAE;AACpB,gBAAA,IAAI,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE;YAC/D;AACA,YAAA,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC;AACzB,QAAA,CAAC,CAAC;AAEF,QAAA,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,MAAK;;;YAGjC,IAAI,IAAI,EAAE;gBACT,IAAI,CAAC,MAAM,EAAE;YACd;AACD,QAAA,CAAC,CAAC;IACH;uGA7HY,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAnB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,mBAAmB,wmDC1DhC,syCAoCA,EAAA,MAAA,EAAA,CAAA,g5JAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FDsBa,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAjB/B,SAAS;AACC,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,aAAa,cACX,IAAI,EAAA,eAAA,EACC,uBAAuB,CAAC,MAAM,EAAA,IAAA,EAGzC;AACL,wBAAA,KAAK,EAAE,aAAa;AACpB,wBAAA,IAAI,EAAE,QAAQ;AACd,wBAAA,WAAW,EAAE,QAAQ;AACrB,wBAAA,WAAW,EAAE,MAAM;AACnB,wBAAA,SAAS,EAAE,oBAAoB;AAC/B,wBAAA,+BAA+B,EAAE,kBAAkB;AACnD,wBAAA,mBAAmB,EAAE,aAAa;AAClC,wBAAA,8BAA8B,EAAE;AAChC,qBAAA,EAAA,QAAA,EAAA,syCAAA,EAAA,MAAA,EAAA,CAAA,g5JAAA,CAAA,EAAA;;;AEvCF;;;;;;;;;;;;;;;;;;;;;;;;;;AA0BG;MAEU,iBAAiB,CAAA;AACZ,IAAA,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC;AAC/B,IAAA,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;AAC3B,IAAA,UAAU,GAAG,MAAM,CAAC,WAAW,CAAC;AAChC,IAAA,MAAM,GAAG,MAAM,CAAC,kBAAkB,CAAC;AAEpD;;;;;;;;;AASG;IACc,OAAO,GAAG,MAAM,CAAC,CAAC;gFAAC;;IAG5B,UAAU,GAA6C,IAAI;AAEnE;;;;AAIG;IACK,OAAO,GAAsB,EAAE;;IAG9B,SAAS,GAAoB,QAAQ,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC;kFAAC;AAExE;;;;;AAKG;IACH,IAAI,CAAC,UAA6B,EAAE,EAAA;AACnC,QAAA,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;AAC1B,QAAA,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,KAAK,KAAK,GAAG,CAAC,CAAC;QACzC,IAAI,CAAC,KAAK,EAAE;IACb;AAEA;;;;AAIG;IACH,IAAI,GAAA;QACH,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QAEtD,IAAI,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YAClC,IAAI,CAAC,OAAO,EAAE;QACf;IACD;;IAGA,OAAO,GAAA;AACN,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QACnB,IAAI,CAAC,OAAO,EAAE;IACf;AAEA;;;;;AAKG;AACH,IAAA,MAAM,CAAC,OAA0B,EAAA;AAChC,QAAA,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;QAC1B,IAAI,CAAC,YAAY,EAAE;IACpB;AAEA;;;;;;AAMG;AACK,IAAA,YAAY,CAAC,OAA0B,EAAA;AAC9C,QAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AACnD,YAAA,IAAI,KAAK,KAAK,SAAS,EAAE;AACvB,gBAAA,IAAI,CAAC,OAAmC,CAAC,GAAG,CAAC,GAAG,KAAK;YACvD;QACD;IACD;AAEA;;;AAGG;IACK,KAAK,GAAA;QACZ,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE;YACxC;QACD;AAEA,QAAA,IAAI,IAAI,CAAC,UAAU,EAAE;YACpB,IAAI,CAAC,YAAY,EAAE;YACnB;QACD;;;AAIA,QAAA,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE;YAC1B;QACD;AAEA,QAAA,MAAM,GAAG,GAAG,eAAe,CAAC,mBAAmB,EAAE,EAAE,mBAAmB,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;AAC/F,QAAA,IAAI,CAAC,UAAU,GAAG,GAAG;QACrB,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC;AACpC,QAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC;QAC1D,IAAI,CAAC,YAAY,EAAE;IACpB;;IAGQ,OAAO,GAAA;AACd,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU;AAC3B,QAAA,IAAI,CAAC,UAAU,GAAG,IAAI;AACtB,QAAA,IAAI,CAAC,OAAO,GAAG,EAAE;QAEjB,IAAI,CAAC,GAAG,EAAE;YACT;QACD;QAEA,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC;QACpC,GAAG,CAAC,OAAO,EAAE;;AAEb,QAAA,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,EAAE;IACpC;AAEA;;;;;;AAMG;IACK,YAAY,GAAA;AACnB,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU;QAE3B,IAAI,CAAC,GAAG,EAAE;YACT;QACD;AAEA,QAAA,MAAM,QAAQ,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE;AACpD,QAAA,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;QAClC,GAAG,CAAC,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC;QACzC,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC;QACrC,GAAG,CAAC,QAAQ,CAAC,gBAAgB,EAAE,QAAQ,CAAC,cAAc,CAAC;QACvD,GAAG,CAAC,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC;QACzC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC;QACnC,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC;QACrC,GAAG,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,QAAQ,CAAC;QAC3C,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,SAAS,CAAC;AAC7C,QAAA,GAAG,CAAC,iBAAiB,CAAC,aAAa,EAAE;IACtC;uGA5JY,iBAAiB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAjB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,iBAAiB,cADJ,MAAM,EAAA,CAAA;;2FACnB,iBAAiB,EAAA,UAAA,EAAA,CAAA;kBAD7B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;ACzClC;;;;;;;;;;;;AAYG;AACG,SAAU,oBAAoB,CAAC,QAAgB,EAAA;AACpD,IAAA,IAAI,QAAQ,GAAG,EAAE,EAAE;AAClB,QAAA,OAAO,EAAE;IACV;AACA,IAAA,IAAI,QAAQ,GAAG,EAAE,EAAE;AAClB,QAAA,OAAO,CAAC;IACT;AACA,IAAA,IAAI,QAAQ,GAAG,EAAE,EAAE;AAClB,QAAA,OAAO,CAAC;IACT;AACA,IAAA,IAAI,QAAQ,GAAG,EAAE,EAAE;AAClB,QAAA,OAAO,GAAG;IACX;AACA,IAAA,OAAO,CAAC;AACT;AAEA;;;;;AAKG;AACI,MAAM,8BAA8B,GAAwB;AAClE,IAAA,GAAG,EAAE,CAAC;AACN,IAAA,GAAG,EAAE,EAAE;AACP,IAAA,YAAY,EAAE,GAAG;AACjB,IAAA,OAAO,EAAE,IAAI;AACb,IAAA,SAAS,EAAE,oBAAoB;AAC/B,IAAA,KAAK,EAAE,GAAG;AACV,IAAA,aAAa,EAAE,GAAG;AAClB,IAAA,KAAK,EAAE,IAAI;AACX,IAAA,IAAI,EAAE,IAAI;AACV,IAAA,SAAS,EAAE;;AAGZ;;;;;AAKG;MACU,sBAAsB,GAAG,IAAI,cAAc,CAAsB,wBAAwB,EAAE;AACvG,IAAA,UAAU,EAAE,MAAM;AAClB,IAAA,OAAO,EAAE,MAAM;AACf,CAAA;AAED;;;;;;AAMG;AACG,SAAU,oBAAoB,CAAC,MAAA,GAAuC,EAAE,EAAA;AAC7E,IAAA,OAAO,wBAAwB,CAAC;AAC/B,QAAA;AACC,YAAA,OAAO,EAAE,sBAAsB;AAC/B,YAAA,QAAQ,EAAE,EAAE,GAAG,8BAA8B,EAAE,GAAG,MAAM;AACxD;AACD,KAAA,CAAC;AACH;;ACrEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCG;MAEU,oBAAoB,CAAA;AACf,IAAA,MAAM,GAAG,MAAM,CAAC,sBAAsB,CAAC;AACvC,IAAA,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC;AACrB,IAAA,UAAU,GAAG,MAAM,CAAC,WAAW,CAAC;;AAGjD;;;;;;;;;AASG;IACc,OAAO,GAAG,MAAM,CAAC,CAAC;gFAAC;;IAGnB,SAAS,GAAG,MAAM,CAAC,CAAC;kFAAC;;IAGrB,QAAQ,GAAG,MAAM,CAAC,KAAK;iFAAC;;AAGxB,IAAA,MAAM,GAAqE;AAC3F,QAAA,MAAM,EAAE,IAAI;AACZ,QAAA,OAAO,EAAE,IAAI;AACb,QAAA,QAAQ,EAAE;KACV;;AAGQ,IAAA,QAAQ,GAAmB,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE;AAE/D;;;AAGG;AACM,IAAA,SAAS,GAAoB,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE;AAEhE;;;AAGG;IACM,QAAQ,GAAoB,QAAQ,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC;iFAAC;AAEvE,IAAA,WAAA,GAAA;;;AAGC,QAAA,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;IAC1D;AAEA;;AAEG;IACH,KAAK,GAAA;QACJ,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;AAC7C,QAAA,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,KAAK,KAAK,GAAG,CAAC,CAAC;QAEzC,IAAI,CAAC,OAAO,EAAE;YACb;QACD;QAEA,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,KAAK,IAAI,EAAE;;;;AAIlC,YAAA,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;AAC3B,YAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;QACzB;QAEA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;QAEnC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE;YACxC;QACD;;;;;QAMA,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,EAAE;YAC3B,IAAI,CAAC,MAAM,EAAE;YACb;QACD;AAEA,QAAA,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;IAChE;AAEA;;;;AAIG;IACH,QAAQ,GAAA;QACP,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QAEtD,IAAI,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YAClC,IAAI,CAAC,MAAM,EAAE;QACd;IACD;;IAGA,WAAW,GAAA;AACV,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QACnB,IAAI,CAAC,MAAM,EAAE;IACd;AAEA;;;;;;;;AAQG;AACH,IAAA,GAAG,CAAC,KAAa,EAAA;QAChB,IAAI,CAAC,MAAM,EAAE;QACb,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IACtD;AAEA;;;;;AAKG;AACH,IAAA,GAAG,CAAC,MAAe,EAAA;QAClB,IAAI,CAAC,MAAM,EAAE;AACb,QAAA,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;IACrB;AAEA;;;AAGG;IACH,KAAK,GAAA;QACJ,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;AACnB,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACxB,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB;;IAGQ,MAAM,GAAA;AACb,QAAA,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;AACzB,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,cAAc,EAAE;IACtB;AAEA;;;;;;AAMG;IACK,MAAM,GAAA;AACb,QAAA,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;AACzB,QAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;;;;QAK1B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;AAC9B,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;YACrB;QACD;AAEA,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;QACvB,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACrF;;IAGQ,cAAc,GAAA;QACrB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,KAAK,IAAI,IAAI,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YAC1F;QACD;QAEA,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE;YACxC;QACD;AAEA,QAAA,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAK;YAChC,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,WAAW,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;AAClF,QAAA,CAAC,CAAC;IACH;;AAGQ,IAAA,OAAO,CAAC,MAAe,EAAA;;;;QAI9B,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC;AACzC,QAAA,MAAM,IAAI,GAAG,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC;QAErD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC;IAC3E;;AAGQ,IAAA,QAAQ,CAAC,IAAwB,EAAE,KAAa,EAAE,MAAkB,EAAA;AAC3E,QAAA,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;AAErB,QAAA,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAK;YAChC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,MAAK;AACnC,gBAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI;AACxB,gBAAA,MAAM,EAAE;YACT,CAAC,EAAE,KAAK,CAAC;AACV,QAAA,CAAC,CAAC;IACH;;AAGQ,IAAA,UAAU,CAAC,IAAwB,EAAA;QAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;AAEhC,QAAA,IAAI,MAAM,KAAK,IAAI,EAAE;YACpB;QACD;AAEA,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI;;;QAGxB,YAAY,CAAC,MAAM,CAAC;QACpB,aAAa,CAAC,MAAwC,CAAC;IACxD;;IAGQ,cAAc,GAAA;AACrB,QAAA,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;AACzB,QAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;AAC1B,QAAA,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;IAC5B;uGAxOY,oBAAoB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAApB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,oBAAoB,cADP,MAAM,EAAA,CAAA;;2FACnB,oBAAoB,EAAA,UAAA,EAAA,CAAA;kBADhC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;ACzClC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCG;MAqBU,sBAAsB,CAAA;;AAEjB,IAAA,MAAM,GAAG,MAAM,CAAC,sBAAsB,CAAC;;AAGvC,IAAA,OAAO,GAAG,MAAM,CAAC,oBAAoB,CAAC;AAEvD;;;AAGG;IACM,IAAI,GAAG,KAAK,CAAoB,QAAQ;6EAAC;;IAGzC,SAAS,GAAG,KAAK,CAAyB,KAAK;kFAAC;AAEzD;;;AAGG;IACM,QAAQ,GAAG,KAAK,CAA4B,SAAS;iFAAC;AAE/D;;;;;AAKG;IACM,aAAa,GAAG,KAAK,CAAC,KAAK,qFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;;AAG7D,IAAA,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAA,EAAA,IAAA,SAAA,GAAA,EAAA,SAAA,EAAA,MAAA,EAAA,8BAAA,EAAA,CAAA,EAAI,SAAS,EAAE,gBAAgB,GAAG;AAExE;;;;AAIG;AACM,IAAA,KAAK,GAAG,KAAK,CAAgB,IAAI,CAAC,MAAM,CAAC,KAAK;8EAAC;;AAG/C,IAAA,SAAS,GAAG,KAAK,CAAS,IAAI,CAAC,MAAM,CAAC,SAAS;kFAAC;;IAGxC,OAAO,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,KAAK,SAAS;gFAAC;;AAGvD,IAAA,MAAM,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;+EAAC;;AAG1F,IAAA,QAAQ,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;iFAAC;;IAGjG,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAA,EAAG,IAAI,CAAC,MAAM,EAAE,CAAA,CAAA,CAAG;8EAAC;AAE9D;;;;;;;AAOG;AACgB,IAAA,eAAe,GAAG,QAAQ,CAAC,MAC7C,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI;wFACjF;;AAGkB,IAAA,gBAAgB,GAAG,QAAQ,CAAC,MAAK;QACnD,MAAM,OAAO,GAAG,CAAC,CAAA,iBAAA,EAAoB,IAAI,CAAC,IAAI,EAAE,CAAA,CAAE,CAAC;AAEnD,QAAA,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,QAAQ,EAAE;YAC7B,OAAO,CAAC,IAAI,CAAC,CAAA,iBAAA,EAAoB,IAAI,CAAC,SAAS,EAAE,CAAA,CAAE,CAAC;QACrD;AACA,QAAA,IAAI,IAAI,CAAC,aAAa,EAAE,EAAE;AACzB,YAAA,OAAO,CAAC,IAAI,CAAC,gCAAgC,CAAC;QAC/C;AACA,QAAA,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE;AAChB,YAAA,OAAO,CAAC,IAAI,CAAC,uBAAuB,CAAC;QACtC;AAEA,QAAA,OAAO,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;IACzB,CAAC;yFAAC;AAEF;;;AAGG;AACgB,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAM,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;gFAAC;uGAxF/D,sBAAsB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAtB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,sBAAsB,k5CC7DnC,sDACA,EAAA,MAAA,EAAA,CAAA,yjFAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FD4Da,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBApBlC,SAAS;AACC,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,iBAAiB,cACf,IAAI,EAAA,eAAA,EACC,uBAAuB,CAAC,MAAM,EAAA,IAAA,EAGzC;AACL,wBAAA,KAAK,EAAE,iBAAiB;AACxB,wBAAA,IAAI,EAAE,aAAa;AACnB,wBAAA,eAAe,EAAE,GAAG;AACpB,wBAAA,eAAe,EAAE,KAAK;AACtB,wBAAA,SAAS,EAAE,oBAAoB;AAC/B,wBAAA,kCAAkC,EAAE,YAAY;AAChD,wBAAA,mBAAmB,EAAE,aAAa;AAClC,wBAAA,sBAAsB,EAAE,mBAAmB;AAC3C,wBAAA,oBAAoB,EAAE,4BAA4B;AAClD,wBAAA,oCAAoC,EAAE,SAAS;AAC/C,wBAAA,kCAAkC,EAAE;AACpC,qBAAA,EAAA,QAAA,EAAA,sDAAA,EAAA,MAAA,EAAA,CAAA,yjFAAA,CAAA,EAAA;;;AEtDF;;;;;;AAMG;AACI,MAAM,oBAAoB,GAAG,IAAI,gBAAgB,CAAU,MAAM,KAAK;AAE7E;;;;;;;;;;AAUG;SACa,oBAAoB,CAAC,OAAA,GAAuB,IAAI,WAAW,EAAE,EAAA;IAC5E,OAAO,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,IAAI,CAAC;AAC/C;AAEA;;;;;;;;;;;;;;;;;AAiBG;MACU,wBAAwB,GAAsB,CAAC,GAAG,EAAE,IAAI,KAAI;IACxE,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAE;AAC1C,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC;IACjB;AAEA,IAAA,MAAM,GAAG,GAAG,MAAM,CAAC,oBAAoB,CAAC;IACxC,GAAG,CAAC,KAAK,EAAE;AAEX,IAAA,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;AACtD;;AC5CA;AACA,SAAS,mBAAmB,CAAC,KAA4B,EAAA;IACxD,QACC,KAAK,YAAY,aAAa;AAC9B,QAAA,KAAK,YAAY,gBAAgB;AACjC,QAAA,KAAK,YAAY,eAAe;QAChC,KAAK,YAAY,iBAAiB;AAEpC;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;AAyBG;SACa,0BAA0B,GAAA;AACzC,IAAA,OAAO,wBAAwB,CAAC;QAC/B,qBAAqB,CAAC,MAAK;AAC1B,YAAA,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AAC7B,YAAA,MAAM,GAAG,GAAG,MAAM,CAAC,oBAAoB,CAAC;YACxC,IAAI,UAAU,GAAG,KAAK;YAEtB,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,KAAI;AACtD,gBAAA,IAAI,KAAK,YAAY,eAAe,EAAE;oBACrC,IAAI,CAAC,UAAU,EAAE;wBAChB,UAAU,GAAG,IAAI;wBACjB,GAAG,CAAC,KAAK,EAAE;oBACZ;oBACA;gBACD;AAEA,gBAAA,IAAI,mBAAmB,CAAC,KAAK,CAAC,IAAI,UAAU,EAAE;oBAC7C,UAAU,GAAG,KAAK;oBAClB,GAAG,CAAC,QAAQ,EAAE;gBACf;AACD,YAAA,CAAC,CAAC;AAEF,YAAA,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,MAAM,YAAY,CAAC,WAAW,EAAE,CAAC;AAC/D,QAAA,CAAC;AACD,KAAA,CAAC;AACH;;ACzEA;;ACAA;;AAEG;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ng-hub-ui-loading",
|
|
3
|
-
"version": "22.
|
|
3
|
+
"version": "22.4.0",
|
|
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 Fernández <carlos.morcillo@me.com> (https://www.carlosmorcillo.com)",
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
"standalone"
|
|
25
25
|
],
|
|
26
26
|
"peerDependencies": {
|
|
27
|
-
"@angular/common": ">=17.
|
|
28
|
-
"@angular/core": ">=17.
|
|
29
|
-
"@angular/router": ">=17.
|
|
27
|
+
"@angular/common": ">=17.3.0",
|
|
28
|
+
"@angular/core": ">=17.3.0",
|
|
29
|
+
"@angular/router": ">=17.3.0",
|
|
30
30
|
"ng-hub-ui-ds": ">=22.0.0",
|
|
31
31
|
"ng-hub-ui-utils": ">=22.8.0",
|
|
32
32
|
"rxjs": ">=7.5.0"
|
|
@@ -6,8 +6,9 @@ import { HttpContextToken, HttpInterceptorFn, HttpContext } from '@angular/commo
|
|
|
6
6
|
* Where the indicator is placed relative to the document.
|
|
7
7
|
*
|
|
8
8
|
* `overlay` positions absolutely, so the **parent must establish a containing
|
|
9
|
-
* block** (`position: relative`); `fullscreen` is fixed to the viewport and
|
|
10
|
-
*
|
|
9
|
+
* block** (`position: relative`); `fullscreen` is fixed to the viewport, and to stay
|
|
10
|
+
* measured against it the indicator leaves its subtree for `appendTo` (`<body>` by
|
|
11
|
+
* default) — the same place {@link HubLoadingService} mounts its own overlay.
|
|
11
12
|
*/
|
|
12
13
|
type HubLoadingMode = 'inline' | 'overlay' | 'fullscreen';
|
|
13
14
|
/** Built-in pure-CSS activity indicators, so the library ships no image assets. */
|
|
@@ -78,6 +79,9 @@ interface HubLoadingConfig {
|
|
|
78
79
|
* out-specify anything. The overlay `HubLoadingService` mounts on `document.body` is a
|
|
79
80
|
* regular instance of this component, so it carries the same stylesheet with it.
|
|
80
81
|
*
|
|
82
|
+
* A `fullscreen` indicator moves to `<body>` for the same reason the service mounts there —
|
|
83
|
+
* see {@link appendTo}.
|
|
84
|
+
*
|
|
81
85
|
* @example
|
|
82
86
|
* ```html
|
|
83
87
|
* <hub-loading variant="dots" message="Loading orders…" />
|
|
@@ -92,7 +96,8 @@ declare class HubLoadingComponent {
|
|
|
92
96
|
private readonly config;
|
|
93
97
|
/**
|
|
94
98
|
* Placement of the indicator. `overlay` needs a positioned ancestor to cover;
|
|
95
|
-
* `fullscreen` is fixed to the viewport
|
|
99
|
+
* `fullscreen` is fixed to the viewport, layered at `--hub-loading-z-index`, and moved to
|
|
100
|
+
* {@link appendTo} so neither of those is decided by an ancestor.
|
|
96
101
|
*/
|
|
97
102
|
readonly mode: _angular_core.InputSignal<HubLoadingMode>;
|
|
98
103
|
/** Built-in CSS indicator rendered when no {@link image} is supplied. */
|
|
@@ -115,6 +120,24 @@ declare class HubLoadingComponent {
|
|
|
115
120
|
readonly backdrop: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
116
121
|
/** Accessible label announced by the host's `role="status"` live region. */
|
|
117
122
|
readonly ariaLabel: _angular_core.InputSignal<string>;
|
|
123
|
+
/**
|
|
124
|
+
* CSS selector of the element a `fullscreen` indicator is re-parented to; `null` leaves it
|
|
125
|
+
* where the template declares it.
|
|
126
|
+
*
|
|
127
|
+
* `position: fixed` measures from the viewport only while no ancestor applies layout
|
|
128
|
+
* containment, a transform or a filter, and it paints over the page only while no ancestor
|
|
129
|
+
* opens a stacking context. A shell cannot promise either — `<hub-side-panel-container>`
|
|
130
|
+
* opens one on purpose, and any card with a `transform` breaks the first — so an indicator
|
|
131
|
+
* declared deep in a page covered its own corner of it rather than the window. Leaving the
|
|
132
|
+
* subtree is the only fix that does not depend on what every ancestor happens to declare, and
|
|
133
|
+
* it is what the family already does with anything that has to float (a select panel, the
|
|
134
|
+
* service's own overlay). `inline` and `overlay` are never moved: they exist to sit where the
|
|
135
|
+
* consumer put them.
|
|
136
|
+
*
|
|
137
|
+
* A selector that matches nothing leaves the indicator in place rather than guessing at
|
|
138
|
+
* another parent.
|
|
139
|
+
*/
|
|
140
|
+
readonly appendTo: _angular_core.InputSignal<string | null>;
|
|
118
141
|
/** Mode and size modifiers; kept as one binding so a size change cannot drop the mode. */
|
|
119
142
|
protected readonly _modifierClasses: _angular_core.Signal<string>;
|
|
120
143
|
/**
|
|
@@ -129,8 +152,9 @@ declare class HubLoadingComponent {
|
|
|
129
152
|
protected readonly _accent: _angular_core.Signal<string | null>;
|
|
130
153
|
/** Motion modifier for the branding image; `none` adds no class at all. */
|
|
131
154
|
protected readonly _imageClasses: _angular_core.Signal<string>;
|
|
155
|
+
constructor();
|
|
132
156
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<HubLoadingComponent, never>;
|
|
133
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<HubLoadingComponent, "hub-loading", never, { "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "image": { "alias": "image"; "required": false; "isSignal": true; }; "imageAnimation": { "alias": "imageAnimation"; "required": false; "isSignal": true; }; "message": { "alias": "message"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "backdrop": { "alias": "backdrop"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
157
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<HubLoadingComponent, "hub-loading", never, { "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "image": { "alias": "image"; "required": false; "isSignal": true; }; "imageAnimation": { "alias": "imageAnimation"; "required": false; "isSignal": true; }; "message": { "alias": "message"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "backdrop": { "alias": "backdrop"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "appendTo": { "alias": "appendTo"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
134
158
|
}
|
|
135
159
|
|
|
136
160
|
/**
|