All files / shell/src/router outlet.ts

100% Statements 81/81
85.71% Branches 6/7
100% Functions 3/3
100% Lines 81/81

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 821x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 14x 14x 14x 14x 14x 14x 14x 14x 14x 14x 14x 14x 14x 1x 1x 14x 14x 14x 14x 14x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x  
import { Factor } from '@sgrud/core';
import { first, from, switchMap } from 'rxjs';
import { customElements } from '../component/registry';
import { Router } from './router';
 
declare global {
  interface HTMLElementTagNameMap {
 
    /**
     * @see {@link RouterOutlet}
     */
    'router-outlet': RouterOutlet;
 
  }
}
 
/**
 * Custom element extending the {@link HTMLSlotElement}. When this element is
 * constructed, it supplies the value of its {@link baseHref} attribute and the
 * presence of a {@link hashBased} attribute on itself to the {@link Router}
 * while {@link Router.connect}ing the {@link Router} to itself. This element
 * should only be used once, as it will be used by the {@link Router} as
 * {@link Router.outlet} to render the current {@link Router.State}.
 *
 * @example
 * A `router-outlet`:
 * ```html
 * <slot baseHref="/example" is="router-outlet">Loading...</slot>
 * ```
 *
 * @see {@link Router}
 */
export class RouterOutlet extends HTMLSlotElement {
 
  /**
   * {@link Factor}ed-in **router** property linking the {@link Router}.
   *
   * @decorator {@link Factor}
   */
  @Factor(() => Router)
  private readonly router!: Router;
 
  /**
   * Getter mirroring the **baseHref** attribute of this element.
   */
  public get baseHref(): string | undefined {
    return this.getAttribute('baseHref') || undefined;
  }
 
  /**
   * Getter mirroring the presence of a **hashBased** attribute on this element.
   */
  public get hashBased(): boolean {
    return this.hasAttribute('hashBased');
  }
 
  /**
   * Public **constructor** of this custom {@link RouterOutlet} element.
   * Supplies the value of its {@link baseHref} attribute and the presence of a
   * {@link hashBased} attribute on itself to the {@link Router} while
   * {@link Router.connect}ing the {@link Router} to itself.
   */
  public constructor() {
    super();
 
    const { hash, pathname, search } = location;
    this.router.connect(this, this.baseHref, this.hashBased);
 
    from(Router).pipe(first(), switchMap(() => {
      return this.router.navigate(pathname + hash, search, 'replace');
    })).subscribe();
  }
 
}
 
/**
 * Registration of this custom element.
 */
customElements.define('router-outlet', RouterOutlet, {
  extends: 'slot'
});