import { html, LitElement } from 'lit'; import type { TemplateResult } from 'lit'; import { property } from 'lit/decorators.js'; import { UIRouterLit } from './core.js'; interface UiRouterContextEventDetail { uiRouter?: UIRouterLit; } /** * @internal */ export type UiRouterContextEvent = CustomEvent; /** * @hideconstructor * * @slot - <ui-router> renders slotted content. * * @fires {CustomEvent} ui-router-context * * <ui-router> listens to the * ui-router-context event * and provides the uiRouter instance. * * @summary * * This is the root ui-router component. * */ export class UIRouterLitElement extends LitElement { /** * Root uiRouter singleton. * If not provided, the element creates and assigns a new instance. */ @property({ attribute: false }) uiRouter: UIRouterLit | undefined; /** @internal */ static uiRouterContextEventName = 'ui-router-context'; /** @internal */ static uiRouterContextEvent(uiRouter?: UIRouterLit): UiRouterContextEvent { return new CustomEvent(this.uiRouterContextEventName, { bubbles: true, composed: true, detail: { uiRouter, }, }); } /** * Discovers the {@link UIRouterLit} instance provided by the nearest * enclosing <ui-router> element. * * Dispatches a bubbling, composed ui-router-context event from * the candidate element; the enclosing <ui-router> * answers it with its router instance. Returns undefined when * the candidate is not inside a <ui-router> (e.g. not * yet connected). * * This is the dependency-injection primitive for integrating external * reactivity systems (state stores, controllers) with the router context — * call it from hostConnected() / connectedCallback() * instead of prop-drilling the router instance. */ static seekRouter(candidate: Element): UIRouterLit | undefined { const uiRouterContextEvent = this.uiRouterContextEvent(); candidate.dispatchEvent(uiRouterContextEvent); return uiRouterContextEvent.detail.uiRouter; } /** @internal */ static onUiRouterContextEvent( uiRouter?: UIRouterLit, ): (event: UiRouterContextEvent) => void { return (event: UiRouterContextEvent) => { event.stopPropagation(); event.detail.uiRouter = uiRouter; }; } private readonly onUiRouterContextEvent = (event: UiRouterContextEvent) => { this.constructor.onUiRouterContextEvent(this.uiRouter)(event); }; /** @internal */ connectedCallback(): void { super.connectedCallback(); this.uiRouter = this.uiRouter || new UIRouterLit(); this.addEventListener( this.constructor.uiRouterContextEventName, this.onUiRouterContextEvent as EventListener, ); this.dispatchEvent(this.constructor.uiRouterContextEvent(this.uiRouter)); } /** @internal */ render(): TemplateResult { return html``; } } export interface UIRouterLitElement { /** @internal */ constructor: typeof UIRouterLitElement; }