ng-hub-ui-loading 22.0.0 → 22.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,6 @@
1
1
  import * as _angular_core from '@angular/core';
2
2
  import { Signal, InjectionToken, EnvironmentProviders } from '@angular/core';
3
+ import { HttpContextToken, HttpInterceptorFn, HttpContext } from '@angular/common/http';
3
4
 
4
5
  /**
5
6
  * Where the indicator is placed relative to the document.
@@ -164,7 +165,16 @@ declare class HubLoadingService {
164
165
  private readonly document;
165
166
  private readonly platformId;
166
167
  private readonly config;
167
- /** Number of callers currently requesting the overlay. */
168
+ /**
169
+ * Number of callers currently requesting the overlay.
170
+ *
171
+ * Read through `untracked` wherever it steers this service's own logic. A caller is not
172
+ * necessarily outside a reactive context — `hide()` from inside an `effect()` is ordinary
173
+ * code — and a tracked read there subscribes that effect to the counter, so anyone else's
174
+ * `show()` re-runs it and retires a reference it never registered, taking the overlay down
175
+ * while other callers are still waiting. Only `isLoading` reads it tracked, and that one is
176
+ * meant to: it exists to be watched.
177
+ */
168
178
  private readonly pending;
169
179
  /** Live reference to the mounted overlay; `null` whenever nothing is showing. */
170
180
  private overlayRef;
@@ -248,5 +258,418 @@ declare const HUB_LOADING_CONFIG: InjectionToken<HubLoadingConfig>;
248
258
  */
249
259
  declare function provideHubLoading(config?: Partial<HubLoadingConfig>): EnvironmentProviders;
250
260
 
251
- export { HUB_LOADING_CONFIG, HUB_LOADING_DEFAULT_CONFIG, HubLoadingComponent, HubLoadingService, provideHubLoading };
252
- export type { HubLoadingConfig, HubLoadingImageAnimation, HubLoadingMode, HubLoadingOptions, HubLoadingSize, HubLoadingVariant };
261
+ /**
262
+ * Where the bar is placed relative to the document.
263
+ *
264
+ * `inline` takes part in normal flow and reserves its own strip, so the page never
265
+ * shifts when the bar appears; `overlay` is absolutely positioned against the nearest
266
+ * positioned ancestor — the classic "hanging off the bottom edge of a navbar" case, and
267
+ * the consumer owns that containing block; `fixed` pins the bar to the viewport, offset
268
+ * by `--hub-loading-bar-offset` so it can sit under a navbar that is itself fixed.
269
+ */
270
+ type HubLoadingBarMode = 'inline' | 'overlay' | 'fixed';
271
+ /** Which edge the `overlay` and `fixed` modes attach to; ignored by `inline`. */
272
+ type HubLoadingBarPlacement = 'top' | 'bottom';
273
+ /**
274
+ * Function deciding how much to advance on each trickle tick.
275
+ *
276
+ * Page loads have no honest percentage — the browser does not know how many bytes are
277
+ * left, and a resolver knows even less. The bar therefore advances in steps that shrink
278
+ * as it fills, so it always seems to be moving while never reaching the end on its own.
279
+ *
280
+ * @param progress - Current value, 0–100.
281
+ * @returns Amount to add, in the same 0–100 scale. Return `0` to stall.
282
+ */
283
+ type HubLoadingBarTrickle = (progress: number) => number;
284
+ /**
285
+ * Application-wide defaults for the loading bar.
286
+ *
287
+ * Fully resolved (no optional members) so the component, the service and the
288
+ * integrations read a value without re-implementing the fallback chain at each call site.
289
+ * Durations are milliseconds; progress values are on a 0–100 scale.
290
+ */
291
+ interface HubLoadingBarConfig {
292
+ /**
293
+ * Value the bar jumps to the instant it appears.
294
+ *
295
+ * Never zero: a bar that starts empty reads as a bar that is not working. The jump is
296
+ * the acknowledgement that the request was received.
297
+ */
298
+ min: number;
299
+ /**
300
+ * Ceiling the trickle may not cross.
301
+ *
302
+ * Below 100 on purpose. Only {@link HubLoadingBarService.complete} knows the work is
303
+ * actually done, so a trickle that reached 100 would promise an ending it cannot
304
+ * deliver and then sit there, full and lying.
305
+ */
306
+ max: number;
307
+ /** Milliseconds between trickle ticks. */
308
+ trickleSpeed: number;
309
+ /** Whether the bar advances on its own while it waits. */
310
+ trickle: boolean;
311
+ /** Step function driving each tick; see {@link HubLoadingBarTrickle}. */
312
+ trickleFn: HubLoadingBarTrickle;
313
+ /**
314
+ * Grace period before the bar is painted at all.
315
+ *
316
+ * Work that finishes inside this window never shows a bar. A 40 ms navigation that
317
+ * flashes a progress bar looks broken, not fast — this is what keeps a cached route
318
+ * from flickering.
319
+ *
320
+ * `0` reveals the bar synchronously rather than on the next macrotask, so a caller who
321
+ * opted out of the grace period still sees it for work that settles within its own task.
322
+ */
323
+ delay: number;
324
+ /**
325
+ * How long the completed bar stays on screen at 100% before it fades away.
326
+ *
327
+ * Wants to be at least `--hub-loading-bar-speed`, or the bar is dismissed before its
328
+ * own fill animation has arrived at the end.
329
+ */
330
+ completeDelay: number;
331
+ /** Default accent: a semantic name, a colour literal or a `var(...)` reference. */
332
+ color: string | null;
333
+ /** Whether the leading edge carries the soft glow that suggests motion. */
334
+ glow: boolean;
335
+ /** Accessible name announced through `role="progressbar"`. */
336
+ ariaLabel: string;
337
+ }
338
+
339
+ /**
340
+ * The thin strip that reports page-level progress — the bar under the navbar.
341
+ *
342
+ * By default the component draws whatever {@link HubLoadingBarService} is doing, which is
343
+ * what makes a single `<hub-loading-bar />` in the shell enough for the whole
344
+ * application: the router integration and the HTTP interceptor drive the service, and
345
+ * this element follows. Bind `progress` to take it over instead, for a bar reporting one
346
+ * known quantity — an upload, an import — independently of everything else.
347
+ *
348
+ * The `progress` input therefore has three meanings, and the difference matters:
349
+ * unbound (`undefined`) follows the service; a number drives the bar directly; `null`
350
+ * hides it. This mirrors how `HubLoadingService` already reads `undefined` as "leave it
351
+ * alone" and `null` as "clear it".
352
+ *
353
+ * Note the deliberate gap in the accessibility contract. While the service is trickling,
354
+ * the number on screen is invented — nothing knows the real percentage of a page load —
355
+ * so `aria-valuenow` is withheld, which is exactly how ARIA spells an indeterminate
356
+ * progressbar. Announcing a made-up "43%" would be worse than announcing nothing. The
357
+ * value is published only when a caller has bound a real one.
358
+ *
359
+ * Styles are unencapsulated, like the rest of the library, so a consumer can retheme the
360
+ * bar from a global stylesheet.
361
+ *
362
+ * @example
363
+ * ```html
364
+ * <!-- Hanging off the bottom edge of a navbar, driven by the service -->
365
+ * <nav class="navbar position-relative">
366
+ * …
367
+ * <hub-loading-bar mode="overlay" placement="bottom" />
368
+ * </nav>
369
+ *
370
+ * <!-- Reporting one known quantity -->
371
+ * <hub-loading-bar [progress]="uploaded()" color="success" />
372
+ * ```
373
+ */
374
+ declare class HubLoadingBarComponent {
375
+ /** Application-wide defaults; also the source of every input's default value. */
376
+ private readonly config;
377
+ /** The shared page-level state this bar renders unless `progress` is bound. */
378
+ private readonly service;
379
+ /**
380
+ * Placement of the strip. `overlay` needs a positioned ancestor to attach to;
381
+ * `fixed` pins it to the viewport at `--hub-loading-bar-offset`.
382
+ */
383
+ readonly mode: _angular_core.InputSignal<HubLoadingBarMode>;
384
+ /** Edge the `overlay` and `fixed` modes attach to; `inline` ignores it. */
385
+ readonly placement: _angular_core.InputSignal<HubLoadingBarPlacement>;
386
+ /**
387
+ * Takes the bar over. Leave it unbound to follow {@link HubLoadingBarService}; bind a
388
+ * number (0–100) to drive it directly, or `null` to hide it.
389
+ */
390
+ readonly progress: _angular_core.InputSignal<number | null | undefined>;
391
+ /**
392
+ * Sweeps a fragment back and forth instead of filling.
393
+ *
394
+ * The honest choice when there is no percentage worth inventing — a long stream, a
395
+ * job with no reported stages.
396
+ */
397
+ readonly indeterminate: _angular_core.InputSignalWithTransform<boolean, unknown>;
398
+ /** Soft glow trailing the leading edge, which is what reads as movement. */
399
+ readonly glow: _angular_core.InputSignalWithTransform<boolean, unknown>;
400
+ /**
401
+ * Accent for the fill. Accepts a semantic name (`primary`), a CSS colour literal or a
402
+ * `var(...)` reference — normalised by `resolveHubAccent()` into the single
403
+ * `--hub-loading-bar-accent` slot.
404
+ */
405
+ readonly color: _angular_core.InputSignal<string | null>;
406
+ /** Accessible name for the host's `role="progressbar"`. */
407
+ readonly ariaLabel: _angular_core.InputSignal<string>;
408
+ /** Whether a caller has taken the bar over rather than following the service. */
409
+ private readonly _manual;
410
+ /** Current fill, from whichever source is in charge. */
411
+ private readonly _value;
412
+ /** Whether the strip is painted at all. */
413
+ protected readonly _visible: _angular_core.Signal<boolean>;
414
+ /** Fill as a CSS length, consumed by the stylesheet's single runtime slot. */
415
+ protected readonly _fill: _angular_core.Signal<string>;
416
+ /**
417
+ * The value published to assistive technology: only ever a real one.
418
+ *
419
+ * `null` removes the attribute, which is how ARIA marks a progressbar indeterminate —
420
+ * the correct answer both while the service trickles an invented number and while the
421
+ * `indeterminate` sweep is running. A bar that is not painted publishes nothing either:
422
+ * the host is `aria-hidden` by then, so a stale value would only ever be misleading.
423
+ */
424
+ protected readonly _announcedValue: _angular_core.Signal<number | null>;
425
+ /** Mode and placement modifiers; kept as one binding so neither can drop the other. */
426
+ protected readonly _modifierClasses: _angular_core.Signal<string>;
427
+ /**
428
+ * Single accent slot consumed by the stylesheet. `null` leaves the binding off
429
+ * entirely, so the token's own cascade default stays in effect.
430
+ */
431
+ protected readonly _accent: _angular_core.Signal<string | null>;
432
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<HubLoadingBarComponent, never>;
433
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<HubLoadingBarComponent, "hub-loading-bar", never, { "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "placement": { "alias": "placement"; "required": false; "isSignal": true; }; "progress": { "alias": "progress"; "required": false; "isSignal": true; }; "indeterminate": { "alias": "indeterminate"; "required": false; "isSignal": true; }; "glow": { "alias": "glow"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
434
+ }
435
+
436
+ /**
437
+ * Drives the page-level loading bar: the thin strip under the navbar that says
438
+ * "something is on its way" without pretending to know how long it will take.
439
+ *
440
+ * Three decisions shape the whole service, and each exists because the naive version is
441
+ * worse:
442
+ *
443
+ * - **Reference counting, not a boolean.** A route change and the three requests its
444
+ * page fires are four independent callers. With a boolean, the first one to finish
445
+ * would take the bar down while the other three were still working. The bar completes
446
+ * when the count reaches zero, and {@link completeAll} is the escape hatch for a caller
447
+ * that never balanced its `start()`.
448
+ * - **A grace period before anything is painted.** Work that finishes within `delay`
449
+ * never shows a bar at all. A cached route that flashes a progress bar for 40 ms reads
450
+ * as a glitch, not as speed.
451
+ * - **A trickle that never reaches the end.** Nothing here knows the real percentage, so
452
+ * the bar advances in shrinking steps and stops at `max`. Only `complete()` may show
453
+ * 100, because only `complete()` knows it is true.
454
+ *
455
+ * Timers run outside the Angular zone. Inside it, a 250 ms interval would trigger change
456
+ * detection for the whole application on every tick and — far worse — would keep
457
+ * `ApplicationRef.isStable` false forever, which hangs server-side rendering. The state
458
+ * is signals, so change detection is still scheduled correctly when a value actually
459
+ * changes. On the server no timer is created at all: the counter stays truthful and the
460
+ * rendered HTML carries no bar to mismatch on hydration.
461
+ *
462
+ * @example
463
+ * ```typescript
464
+ * private readonly bar = inject(HubLoadingBarService);
465
+ *
466
+ * async import(): Promise<void> {
467
+ * this.bar.start();
468
+ * try {
469
+ * await this.api.import();
470
+ * } finally {
471
+ * this.bar.complete();
472
+ * }
473
+ * }
474
+ * ```
475
+ */
476
+ declare class HubLoadingBarService {
477
+ private readonly config;
478
+ private readonly zone;
479
+ private readonly platformId;
480
+ /** Number of callers currently waiting on something. */
481
+ /**
482
+ * How many callers are holding the bar up.
483
+ *
484
+ * Read through `untracked` everywhere it steers this service's own logic. A caller is
485
+ * not necessarily outside a reactive context — Angular does not untrack interceptors,
486
+ * so a request fired from inside an `effect()` runs `start()` inside that effect — and a
487
+ * tracked read there subscribes the caller's effect to this counter. Every later request
488
+ * then re-runs it, which is a request loop with the bar as the feedback path. Only
489
+ * `isActive` reads it tracked, and that one is meant to: it exists to be watched.
490
+ */
491
+ private readonly pending;
492
+ /** Current fill, 0–100. */
493
+ private readonly _progress;
494
+ /** Whether the bar is painted right now; false during the grace period. */
495
+ private readonly _visible;
496
+ /** Handles of the running timers, so each can be cancelled independently. */
497
+ private readonly timers;
498
+ /** Current fill, 0–100. Bound by `<hub-loading-bar>`; safe to read during SSR. */
499
+ readonly progress: Signal<number>;
500
+ /**
501
+ * Whether the bar is on screen. Differs from {@link isActive} at both ends of a cycle:
502
+ * false while the grace period runs, and still true during the completion tail.
503
+ */
504
+ readonly isVisible: Signal<boolean>;
505
+ /**
506
+ * Whether any caller is still waiting — the honest "is the page loading?" question,
507
+ * regardless of whether the bar has decided to show itself yet.
508
+ */
509
+ readonly isActive: Signal<boolean>;
510
+ constructor();
511
+ /**
512
+ * Registers one caller. The first one starts a cycle; the rest simply join the count.
513
+ */
514
+ start(): void;
515
+ /**
516
+ * Retires one caller. Once none are left the bar runs to 100% and fades away — or, if
517
+ * the grace period swallowed the whole operation, disappears without ever having been
518
+ * seen.
519
+ */
520
+ complete(): void;
521
+ /** Drops every pending caller and completes the bar immediately. */
522
+ completeAll(): void;
523
+ /**
524
+ * Moves the bar to an exact value and reveals it, bypassing the grace period.
525
+ *
526
+ * For work whose real percentage is known — a file upload, a paged import. The value
527
+ * is not capped at `max`, because a caller reporting a true 100 is not guessing;
528
+ * finishing the cycle is still {@link complete}'s job.
529
+ *
530
+ * @param value - Target fill, 0–100. Values outside the range are clamped.
531
+ */
532
+ set(value: number): void;
533
+ /**
534
+ * Advances the bar and reveals it, bypassing the grace period.
535
+ *
536
+ * @param amount - Step to add. Omitted, the configured trickle curve decides, which is
537
+ * what makes an unknown wait keep moving without ever arriving.
538
+ */
539
+ inc(amount?: number): void;
540
+ /**
541
+ * Cancels everything at once: no completion animation, no pending callers, nothing on
542
+ * screen. For an error handler that wants the bar gone rather than finished.
543
+ */
544
+ reset(): void;
545
+ /** Paints the bar and starts the trickle, if a caller is waiting on one. */
546
+ private reveal;
547
+ /**
548
+ * Runs the completion, shared by {@link complete} and {@link completeAll}.
549
+ *
550
+ * The fill is deliberately left at 100 once the bar is hidden. `start()` rewinds it
551
+ * while the bar is invisible, where the stylesheet suppresses the transition, so the
552
+ * next cycle begins from `min` without the previous one being seen to unwind.
553
+ */
554
+ private finish;
555
+ /** Starts the trickle interval, unless it is disabled, already running or unneeded. */
556
+ private startTrickling;
557
+ /** Adds one step, capped at `max` so the trickle can never claim to be finished. */
558
+ private advance;
559
+ /** Schedules a one-shot timer outside the Angular zone, replacing any previous one. */
560
+ private schedule;
561
+ /** Cancels one timer if it is running. Safe to call for a timer that is not. */
562
+ private clearTimer;
563
+ /** Cancels every timer; used by `reset()` and on injector teardown. */
564
+ private clearAllTimers;
565
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<HubLoadingBarService, never>;
566
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<HubLoadingBarService>;
567
+ }
568
+
569
+ /**
570
+ * Default trickle curve: large steps early, then progressively smaller ones.
571
+ *
572
+ * The shape is what makes an invented number believable. Moving fast at the start
573
+ * matches the part of a page load that really is fast (the request goes out, the shell
574
+ * responds); slowing near the end matches the part nobody can predict, and leaves room
575
+ * for `complete()` to arrive without the bar having to jump backwards.
576
+ *
577
+ * Exported so a consumer can wrap it rather than rewrite it.
578
+ *
579
+ * @param progress - Current value, 0–100.
580
+ * @returns Amount to add on this tick.
581
+ */
582
+ declare function hubLoadingBarTrickle(progress: number): number;
583
+ /**
584
+ * Neutral defaults applied when an application provides no configuration.
585
+ *
586
+ * These are the values documented as each input's default, so overriding the token
587
+ * silently re-bases the whole application without touching a template.
588
+ */
589
+ declare const HUB_LOADING_BAR_DEFAULT_CONFIG: HubLoadingBarConfig;
590
+ /**
591
+ * Resolved defaults shared by `<hub-loading-bar>` and `HubLoadingBarService`.
592
+ *
593
+ * Declared with a root factory so the token is always injectable, even when the
594
+ * application never calls {@link provideHubLoadingBar}.
595
+ */
596
+ declare const HUB_LOADING_BAR_CONFIG: InjectionToken<HubLoadingBarConfig>;
597
+ /**
598
+ * Registers application-wide loading-bar defaults — the accent, the pacing, the
599
+ * translated label — so individual call sites stay bare.
600
+ *
601
+ * @param config - Values overriding {@link HUB_LOADING_BAR_DEFAULT_CONFIG}; omitted keys keep their default.
602
+ * @returns Environment providers for the application bootstrap.
603
+ */
604
+ declare function provideHubLoadingBar(config?: Partial<HubLoadingBarConfig>): EnvironmentProviders;
605
+
606
+ /**
607
+ * Marks a request as invisible to the loading bar.
608
+ *
609
+ * The escape hatch is not a nicety. A poll on a timer, a heartbeat, an autosave — any
610
+ * request the reader did not ask for — would otherwise hold the bar open forever, and a
611
+ * progress bar that never finishes is worse than none.
612
+ */
613
+ declare const HUB_LOADING_BAR_SKIP: HttpContextToken<boolean>;
614
+ /**
615
+ * Builds the `HttpContext` that hides one request from the loading bar.
616
+ *
617
+ * @param context - Existing context to extend; a fresh one by default.
618
+ * @returns The context, with the skip flag set.
619
+ *
620
+ * @example
621
+ * ```typescript
622
+ * this.http.get('/api/notifications', { context: withoutHubLoadingBar() });
623
+ * ```
624
+ */
625
+ declare function withoutHubLoadingBar(context?: HttpContext): HttpContext;
626
+ /**
627
+ * Holds the loading bar open for the lifetime of every HTTP request.
628
+ *
629
+ * The bar's reference counter is what makes this safe to combine with the router
630
+ * integration and with hand-written `start()` calls: six parallel requests are six
631
+ * callers, and the bar completes when the last of them does, not the first.
632
+ *
633
+ * `finalize` is the balancing point rather than a `tap` on success, because it also fires
634
+ * when the request errors and when the caller unsubscribes — a cancelled typeahead is the
635
+ * commonest way a naive interceptor strands the bar at 90%.
636
+ *
637
+ * Opt a request out with {@link withoutHubLoadingBar}.
638
+ *
639
+ * @example
640
+ * ```typescript
641
+ * provideHttpClient(withInterceptors([hubLoadingBarInterceptor]))
642
+ * ```
643
+ */
644
+ declare const hubLoadingBarInterceptor: HttpInterceptorFn;
645
+
646
+ /**
647
+ * Drives the loading bar from router navigation, which is the "page is loading" the bar
648
+ * is named after: it starts when a navigation begins and completes when it settles —
649
+ * including when it is cancelled by a guard or fails, because a bar left running after a
650
+ * rejected navigation is a bar that never goes away.
651
+ *
652
+ * Navigations are tracked with a flag rather than by pairing events one-to-one. The
653
+ * router's event sequence varies with configuration (a blocking initial navigation, a
654
+ * redirect, a skipped same-URL navigation), and the flag guarantees exactly one
655
+ * `start()` / `complete()` pair per navigation whatever order the events arrive in — a
656
+ * missed `NavigationStart` during bootstrap can no longer leave an unmatched `complete()`
657
+ * decrementing somebody else's count.
658
+ *
659
+ * Combine with {@link hubLoadingBarInterceptor} when routes fetch their own data: the
660
+ * navigation settles as soon as the component is created, so without the interceptor the
661
+ * bar finishes while the page is still empty.
662
+ *
663
+ * @returns Environment providers for the application bootstrap.
664
+ *
665
+ * @example
666
+ * ```typescript
667
+ * bootstrapApplication(AppComponent, {
668
+ * providers: [provideRouter(routes), provideHubLoadingBarRouter()]
669
+ * });
670
+ * ```
671
+ */
672
+ declare function provideHubLoadingBarRouter(): EnvironmentProviders;
673
+
674
+ export { HUB_LOADING_BAR_CONFIG, HUB_LOADING_BAR_DEFAULT_CONFIG, HUB_LOADING_BAR_SKIP, HUB_LOADING_CONFIG, HUB_LOADING_DEFAULT_CONFIG, HubLoadingBarComponent, HubLoadingBarService, HubLoadingComponent, HubLoadingService, hubLoadingBarInterceptor, hubLoadingBarTrickle, provideHubLoading, provideHubLoadingBar, provideHubLoadingBarRouter, withoutHubLoadingBar };
675
+ export type { HubLoadingBarConfig, HubLoadingBarMode, HubLoadingBarPlacement, HubLoadingBarTrickle, HubLoadingConfig, HubLoadingImageAnimation, HubLoadingMode, HubLoadingOptions, HubLoadingSize, HubLoadingVariant };