UNPKG

@angular/router

Version:
1,987 lines 63.2 kB
/**
 * @license Angular v22.1.4
 * (c) 2010-2026 Google LLC. https://angular.dev/
 * License: MIT
 */

import * as i3 from '@angular/common';
import { ViewportScroller, PlatformNavigation, PlatformLocation, ɵPRECOMMIT_HANDLER_SUPPORTED as _PRECOMMIT_HANDLER_SUPPORTED, Location, LOCATION_INITIALIZED, ɵNavigationAdapterForLocation as _NavigationAdapterForLocation, HashLocationStrategy, LocationStrategy, PathLocationStrategy } from '@angular/common';
import * as i0 from '@angular/core';
import { inject, HostAttributeToken, linkedSignal, untracked, signal, input, ɵINTERNAL_APPLICATION_ERROR_HANDLER as _INTERNAL_APPLICATION_ERROR_HANDLER, effect, ɵRuntimeError as _RuntimeError, computed, booleanAttribute, Service, HostListener, Input, Attribute, Directive, EventEmitter, Output, ContentChildren, reflectComponentType, assertInInjectionContext, Injector, resourceFromSnapshots, DestroyRef, createEnvironmentInjector, runInInjectionContext, Injectable, InjectionToken, ɵIS_HYDRATION_DOM_REUSE_ENABLED as _IS_HYDRATION_DOM_REUSE_ENABLED, NgZone, ApplicationRef, EnvironmentInjector, afterNextRender, ɵpromiseWithResolvers as _promiseWithResolvers, ɵpublishNonCoreGlobalUtil as _publishNonCoreGlobalUtil, makeEnvironmentProviders, APP_BOOTSTRAP_LISTENER, provideAppInitializer, ɵIS_ENABLED_BLOCKING_INITIAL_NAVIGATION as _IS_ENABLED_BLOCKING_INITIAL_NAVIGATION, provideEnvironmentInitializer, ɵperformanceMarkFeature as _performanceMarkFeature, ENVIRONMENT_INITIALIZER, NgModule } from '@angular/core';
import { ROUTER_CONFIGURATION, isUrlTree, Router, ActivatedRoute, StateManager, UrlSerializer, NavigationEnd, UrlTree, isActive, subsetMatchOptions, exactMatchOptions, NavigationStart, NavigationSkipped, NavigationCancel, NavigationError, NavigationCancellationCode, switchTap, initializeActivatedRoute, RouterConfigLoader, IMPERATIVE_NAVIGATION, NavigationTransitions, NavigationSkippedCode, Scroll, BeforeRoutesRecognized, BeforeActivateRoutes, isRedirectingEvent, ROUTES, afterNextNavigation, NAVIGATION_ERROR_HANDLER, routeInjectorCleanup, ROUTE_INJECTOR_CLEANUP, RoutedComponentInputBinder, INPUT_BINDER, createViewTransition, CREATE_VIEW_TRANSITION, VIEW_TRANSITION_OPTIONS, ROUTER_RESOURCES_FEATURE, stringifyEvent, DefaultUrlSerializer, ChildrenOutletContexts, RouterOutlet, ɵEmptyOutletComponent as _EmptyOutletComponent } from './_router-chunk.mjs';
import { Subject, of, from, pipe } from 'rxjs';
import { mergeAll, catchError, filter, concatMap, mergeMap } from 'rxjs/operators';

class ReactiveRouterState {
  router = inject(Router);
  stateManager = inject(StateManager);
  fragment = signal('', ...(ngDevMode ? [{
    debugName: "fragment"
  }] : []));
  queryParams = signal({}, ...(ngDevMode ? [{
    debugName: "queryParams"
  }] : []));
  path = signal('', ...(ngDevMode ? [{
    debugName: "path"
  }] : []));
  serializer = inject(UrlSerializer);
  constructor() {
    this.updateState();
    this.router.events?.subscribe(e => {
      if (e instanceof NavigationEnd) {
        this.updateState();
      }
    });
  }
  updateState() {
    const {
      fragment,
      root,
      queryParams
    } = this.stateManager.getCurrentUrlTree();
    this.fragment.set(fragment);
    this.queryParams.set(queryParams);
    this.path.set(this.serializer.serialize(new UrlTree(root)));
  }
  static ɵfac = i0.ɵɵngDeclareFactory({
    minVersion: "12.0.0",
    version: "22.1.4",
    ngImport: i0,
    type: ReactiveRouterState,
    deps: [],
    target: i0.ɵɵFactoryTarget.Service
  });
  static ɵprov = i0.ɵɵngDeclareService({
    minVersion: "22.0.0",
    version: "22.1.4",
    ngImport: i0,
    type: ReactiveRouterState
  });
}
i0.ɵɵngDeclareClassMetadata({
  minVersion: "12.0.0",
  version: "22.1.4",
  ngImport: i0,
  type: ReactiveRouterState,
  decorators: [{
    type: Service
  }],
  ctorParameters: () => []
});
class RouterLink {
  router;
  route;
  tabIndexAttribute;
  renderer;
  el;
  locationStrategy;
  hrefAttributeValue = inject(new HostAttributeToken('href'), {
    optional: true
  });
  reactiveHref = linkedSignal(() => {
    if (!this.isAnchorElement) {
      return this.hrefAttributeValue;
    }
    return this.computeHref(this._urlTree());
  }, ...(ngDevMode ? [{
    debugName: "reactiveHref"
  }] : []));
  get href() {
    return untracked(this.reactiveHref);
  }
  set href(value) {
    this.reactiveHref.set(value);
  }
  set target(value) {
    this._target.set(value);
  }
  get target() {
    return untracked(this._target);
  }
  _target = signal(undefined, ...(ngDevMode ? [{
    debugName: "_target"
  }] : []));
  set queryParams(value) {
    this._queryParams.set(value);
  }
  get queryParams() {
    return untracked(this._queryParams);
  }
  _queryParams = signal(undefined, {
    ...(ngDevMode ? {
      debugName: "_queryParams"
    } : {}),
    equal: () => false
  });
  set fragment(value) {
    this._fragment.set(value);
  }
  get fragment() {
    return untracked(this._fragment);
  }
  _fragment = signal(undefined, ...(ngDevMode ? [{
    debugName: "_fragment"
  }] : []));
  set queryParamsHandling(value) {
    this._queryParamsHandling.set(value);
  }
  get queryParamsHandling() {
    return untracked(this._queryParamsHandling);
  }
  _queryParamsHandling = signal(undefined, ...(ngDevMode ? [{
    debugName: "_queryParamsHandling"
  }] : []));
  set state(value) {
    this._state.set(value);
  }
  get state() {
    return untracked(this._state);
  }
  _state = signal(undefined, {
    ...(ngDevMode ? {
      debugName: "_state"
    } : {}),
    equal: () => false
  });
  set info(value) {
    this._info.set(value);
  }
  get info() {
    return untracked(this._info);
  }
  _info = signal(undefined, {
    ...(ngDevMode ? {
      debugName: "_info"
    } : {}),
    equal: () => false
  });
  set relativeTo(value) {
    this._relativeTo.set(value);
  }
  get relativeTo() {
    return untracked(this._relativeTo);
  }
  _relativeTo = signal(undefined, ...(ngDevMode ? [{
    debugName: "_relativeTo"
  }] : []));
  set preserveFragment(value) {
    this._preserveFragment.set(value);
  }
  get preserveFragment() {
    return untracked(this._preserveFragment);
  }
  _preserveFragment = signal(false, ...(ngDevMode ? [{
    debugName: "_preserveFragment"
  }] : []));
  set skipLocationChange(value) {
    this._skipLocationChange.set(value);
  }
  get skipLocationChange() {
    return untracked(this._skipLocationChange);
  }
  _skipLocationChange = signal(false, ...(ngDevMode ? [{
    debugName: "_skipLocationChange"
  }] : []));
  set replaceUrl(value) {
    this._replaceUrl.set(value);
  }
  get replaceUrl() {
    return untracked(this._replaceUrl);
  }
  _replaceUrl = signal(false, ...(ngDevMode ? [{
    debugName: "_replaceUrl"
  }] : []));
  browserUrl = input(undefined, ...(ngDevMode ? [{
    debugName: "browserUrl"
  }] : []));
  isAnchorElement;
  onChanges = new Subject();
  applicationErrorHandler = inject(_INTERNAL_APPLICATION_ERROR_HANDLER);
  options = inject(ROUTER_CONFIGURATION, {
    optional: true
  });
  reactiveRouterState = inject(ReactiveRouterState);
  constructor(router, route, tabIndexAttribute, renderer, el, locationStrategy) {
    this.router = router;
    this.route = route;
    this.tabIndexAttribute = tabIndexAttribute;
    this.renderer = renderer;
    this.el = el;
    this.locationStrategy = locationStrategy;
    const tagName = el.nativeElement.tagName?.toLowerCase();
    this.isAnchorElement = tagName === 'a' || tagName === 'area' || !!(typeof customElements === 'object' && customElements.get(tagName)?.observedAttributes?.includes?.('href'));
    if (typeof ngDevMode !== 'undefined' && ngDevMode) {
      effect(() => {
        if (isUrlTree(this.routerLinkInput()) && (this._fragment() !== undefined || this._queryParams() || this._queryParamsHandling() || this._preserveFragment() || this._relativeTo())) {
          throw new _RuntimeError(4017, 'Cannot configure queryParams or fragment when using a UrlTree as the routerLink input value.');
        }
      });
    }
  }
  setTabIndexIfNotOnNativeEl(newTabIndex) {
    if (this.tabIndexAttribute != null || this.isAnchorElement) {
      return;
    }
    this.applyAttributeValue('tabindex', newTabIndex);
  }
  ngOnChanges(changes) {
    this.onChanges.next(this);
  }
  routerLinkInput = signal(null, ...(ngDevMode ? [{
    debugName: "routerLinkInput"
  }] : []));
  set routerLink(commandsOrUrlTree) {
    if (commandsOrUrlTree == null) {
      this.routerLinkInput.set(null);
      this.setTabIndexIfNotOnNativeEl(null);
    } else {
      if (isUrlTree(commandsOrUrlTree)) {
        this.routerLinkInput.set(commandsOrUrlTree);
      } else {
        this.routerLinkInput.set(Array.isArray(commandsOrUrlTree) ? commandsOrUrlTree : [commandsOrUrlTree]);
      }
      this.setTabIndexIfNotOnNativeEl('0');
    }
  }
  onClick(button, ctrlKey, shiftKey, altKey, metaKey) {
    const urlTree = this._urlTree();
    if (urlTree === null) {
      return true;
    }
    if (this.isAnchorElement) {
      if (button !== 0 || ctrlKey || shiftKey || altKey || metaKey) {
        return true;
      }
      if (typeof this.target === 'string' && this.target != '_self') {
        return true;
      }
    }
    const browserUrl = this.browserUrl();
    const extras = {
      skipLocationChange: this.skipLocationChange,
      replaceUrl: this.replaceUrl,
      state: this.state,
      info: this.info,
      ...(browserUrl !== undefined && {
        browserUrl
      })
    };
    this.router.navigateByUrl(urlTree, extras)?.catch(e => {
      this.applicationErrorHandler(e);
    });
    return !this.isAnchorElement;
  }
  ngOnDestroy() {}
  applyAttributeValue(attrName, attrValue) {
    const renderer = this.renderer;
    const nativeElement = this.el.nativeElement;
    if (attrValue !== null) {
      renderer.setAttribute(nativeElement, attrName, attrValue);
    } else {
      renderer.removeAttribute(nativeElement, attrName);
    }
  }
  _urlTree = computed(() => {
    this.reactiveRouterState.path();
    if (this._preserveFragment()) {
      this.reactiveRouterState.fragment();
    }
    const shouldTrackParams = handling => handling === 'preserve' || handling === 'merge';
    if (shouldTrackParams(this._queryParamsHandling()) || shouldTrackParams(this.options?.defaultQueryParamsHandling)) {
      this.reactiveRouterState.queryParams();
    }
    const routerLinkInput = this.routerLinkInput();
    if (routerLinkInput === null || !this.router.createUrlTree) {
      return null;
    } else if (isUrlTree(routerLinkInput)) {
      return routerLinkInput;
    }
    return this.router.createUrlTree(routerLinkInput, {
      relativeTo: this._relativeTo() !== undefined ? this._relativeTo() : this.route,
      queryParams: this._queryParams(),
      fragment: this._fragment(),
      queryParamsHandling: this._queryParamsHandling(),
      preserveFragment: this._preserveFragment()
    });
  }, {
    ...(ngDevMode ? {
      debugName: "_urlTree"
    } : {}),
    equal: (a, b) => this.computeHref(a) === this.computeHref(b)
  });
  get urlTree() {
    return untracked(this._urlTree);
  }
  computeHref(urlTree) {
    return urlTree !== null && this.locationStrategy ? this.locationStrategy?.prepareExternalUrl(this.router.serializeUrl(urlTree)) ?? '' : null;
  }
  static ɵfac = i0.ɵɵngDeclareFactory({
    minVersion: "12.0.0",
    version: "22.1.4",
    ngImport: i0,
    type: RouterLink,
    deps: [{
      token: Router
    }, {
      token: ActivatedRoute
    }, {
      token: 'tabindex',
      attribute: true
    }, {
      token: i0.Renderer2
    }, {
      token: i0.ElementRef
    }, {
      token: i3.LocationStrategy
    }],
    target: i0.ɵɵFactoryTarget.Directive
  });
  static ɵdir = i0.ɵɵngDeclareDirective({
    minVersion: "17.1.0",
    version: "22.1.4",
    type: RouterLink,
    isStandalone: true,
    selector: "[routerLink]",
    inputs: {
      target: {
        classPropertyName: "target",
        publicName: "target",
        isSignal: false,
        isRequired: false,
        transformFunction: null
      },
      queryParams: {
        classPropertyName: "queryParams",
        publicName: "queryParams",
        isSignal: false,
        isRequired: false,
        transformFunction: null
      },
      fragment: {
        classPropertyName: "fragment",
        publicName: "fragment",
        isSignal: false,
        isRequired: false,
        transformFunction: null
      },
      queryParamsHandling: {
        classPropertyName: "queryParamsHandling",
        publicName: "queryParamsHandling",
        isSignal: false,
        isRequired: false,
        transformFunction: null
      },
      state: {
        classPropertyName: "state",
        publicName: "state",
        isSignal: false,
        isRequired: false,
        transformFunction: null
      },
      info: {
        classPropertyName: "info",
        publicName: "info",
        isSignal: false,
        isRequired: false,
        transformFunction: null
      },
      relativeTo: {
        classPropertyName: "relativeTo",
        publicName: "relativeTo",
        isSignal: false,
        isRequired: false,
        transformFunction: null
      },
      preserveFragment: {
        classPropertyName: "preserveFragment",
        publicName: "preserveFragment",
        isSignal: false,
        isRequired: false,
        transformFunction: booleanAttribute
      },
      skipLocationChange: {
        classPropertyName: "skipLocationChange",
        publicName: "skipLocationChange",
        isSignal: false,
        isRequired: false,
        transformFunction: booleanAttribute
      },
      replaceUrl: {
        classPropertyName: "replaceUrl",
        publicName: "replaceUrl",
        isSignal: false,
        isRequired: false,
        transformFunction: booleanAttribute
      },
      browserUrl: {
        classPropertyName: "browserUrl",
        publicName: "browserUrl",
        isSignal: true,
        isRequired: false,
        transformFunction: null
      },
      routerLink: {
        classPropertyName: "routerLink",
        publicName: "routerLink",
        isSignal: false,
        isRequired: false,
        transformFunction: null
      }
    },
    host: {
      listeners: {
        "click": "onClick($event.button,$event.ctrlKey,$event.shiftKey,$event.altKey,$event.metaKey)"
      },
      properties: {
        "attr.href": "reactiveHref()",
        "attr.target": "_target()"
      }
    },
    usesOnChanges: true,
    ngImport: i0
  });
}
i0.ɵɵngDeclareClassMetadata({
  minVersion: "12.0.0",
  version: "22.1.4",
  ngImport: i0,
  type: RouterLink,
  decorators: [{
    type: Directive,
    args: [{
      selector: '[routerLink]',
      host: {
        '[attr.href]': 'reactiveHref()',
        '[attr.target]': '_target()'
      }
    }]
  }],
  ctorParameters: () => [{
    type: Router
  }, {
    type: ActivatedRoute
  }, {
    type: undefined,
    decorators: [{
      type: Attribute,
      args: ['tabindex']
    }]
  }, {
    type: i0.Renderer2
  }, {
    type: i0.ElementRef
  }, {
    type: i3.LocationStrategy
  }],
  propDecorators: {
    target: [{
      type: Input
    }],
    queryParams: [{
      type: Input
    }],
    fragment: [{
      type: Input
    }],
    queryParamsHandling: [{
      type: Input
    }],
    state: [{
      type: Input
    }],
    info: [{
      type: Input
    }],
    relativeTo: [{
      type: Input
    }],
    preserveFragment: [{
      type: Input,
      args: [{
        transform: booleanAttribute
      }]
    }],
    skipLocationChange: [{
      type: Input,
      args: [{
        transform: booleanAttribute
      }]
    }],
    replaceUrl: [{
      type: Input,
      args: [{
        transform: booleanAttribute
      }]
    }],
    browserUrl: [{
      type: i0.Input,
      args: [{
        isSignal: true,
        alias: "browserUrl",
        required: false
      }]
    }],
    routerLink: [{
      type: Input
    }],
    onClick: [{
      type: HostListener,
      args: ['click', ['$event.button', '$event.ctrlKey', '$event.shiftKey', '$event.altKey', '$event.metaKey']]
    }]
  }
});

class RouterLinkActive {
  router;
  element;
  renderer;
  cdr;
  links;
  classes = [];
  routerEventsSubscription;
  linkInputChangesSubscription;
  _isActive = false;
  get isActive() {
    return this._isActive;
  }
  routerLinkActiveOptions = {
    exact: false
  };
  ariaCurrentWhenActive;
  isActiveChange = new EventEmitter();
  link = inject(RouterLink, {
    optional: true
  });
  constructor(router, element, renderer, cdr) {
    this.router = router;
    this.element = element;
    this.renderer = renderer;
    this.cdr = cdr;
    this.routerEventsSubscription = router.events.subscribe(s => {
      if (s instanceof NavigationEnd) {
        this.update();
      }
    });
  }
  ngAfterContentInit() {
    of(this.links.changes, of(null)).pipe(mergeAll()).subscribe(_ => {
      this.update();
      this.subscribeToEachLinkOnChanges();
    });
  }
  subscribeToEachLinkOnChanges() {
    this.linkInputChangesSubscription?.unsubscribe();
    const allLinkChanges = [...this.links.toArray(), this.link].filter(link => !!link).map(link => link.onChanges);
    this.linkInputChangesSubscription = from(allLinkChanges).pipe(mergeAll()).subscribe(link => {
      if (this._isActive !== this.isLinkActive(this.router)(link)) {
        this.update();
      }
    });
  }
  set routerLinkActive(data) {
    if (data == null) {
      this.classes = [];
      return;
    }
    const classes = Array.isArray(data) ? data : data.split(' ');
    this.classes = classes.filter(c => !!c);
  }
  ngOnChanges(changes) {
    this.update();
  }
  ngOnDestroy() {
    this.routerEventsSubscription.unsubscribe();
    this.linkInputChangesSubscription?.unsubscribe();
  }
  update() {
    if (!this.links || !this.router.navigated) return;
    if (this.routerLinkActiveOptions === null && !this._isActive) return;
    queueMicrotask(() => {
      const hasActiveLinks = this.hasActiveLinks();
      this.classes.forEach(c => {
        if (hasActiveLinks) {
          this.renderer.addClass(this.element.nativeElement, c);
        } else {
          this.renderer.removeClass(this.element.nativeElement, c);
        }
      });
      if (hasActiveLinks && this.ariaCurrentWhenActive !== undefined) {
        this.renderer.setAttribute(this.element.nativeElement, 'aria-current', this.ariaCurrentWhenActive.toString());
      } else {
        this.renderer.removeAttribute(this.element.nativeElement, 'aria-current');
      }
      if (this._isActive !== hasActiveLinks) {
        this._isActive = hasActiveLinks;
        this.cdr.markForCheck();
        this.isActiveChange.emit(hasActiveLinks);
      }
    });
  }
  isLinkActive(router) {
    const opts = this.routerLinkActiveOptions;
    if (opts === null) {
      return () => false;
    }
    let options;
    if (opts === undefined) {
      options = {
        ...subsetMatchOptions
      };
    } else if (isActiveMatchOptions(opts)) {
      options = opts;
    } else if (opts.exact ?? false) {
      options = {
        ...exactMatchOptions
      };
    } else {
      options = {
        ...subsetMatchOptions
      };
    }
    return link => {
      const urlTree = link.urlTree;
      return urlTree ? untracked(isActive(urlTree, router, options)) : false;
    };
  }
  hasActiveLinks() {
    const isActiveCheckFn = this.isLinkActive(this.router);
    return this.link && isActiveCheckFn(this.link) || this.links.some(isActiveCheckFn);
  }
  static ɵfac = i0.ɵɵngDeclareFactory({
    minVersion: "12.0.0",
    version: "22.1.4",
    ngImport: i0,
    type: RouterLinkActive,
    deps: [{
      token: Router
    }, {
      token: i0.ElementRef
    }, {
      token: i0.Renderer2
    }, {
      token: i0.ChangeDetectorRef
    }],
    target: i0.ɵɵFactoryTarget.Directive
  });
  static ɵdir = i0.ɵɵngDeclareDirective({
    minVersion: "14.0.0",
    version: "22.1.4",
    type: RouterLinkActive,
    isStandalone: true,
    selector: "[routerLinkActive]",
    inputs: {
      routerLinkActiveOptions: "routerLinkActiveOptions",
      ariaCurrentWhenActive: "ariaCurrentWhenActive",
      routerLinkActive: "routerLinkActive"
    },
    outputs: {
      isActiveChange: "isActiveChange"
    },
    queries: [{
      propertyName: "links",
      predicate: RouterLink,
      descendants: true
    }],
    exportAs: ["routerLinkActive"],
    usesOnChanges: true,
    ngImport: i0
  });
}
i0.ɵɵngDeclareClassMetadata({
  minVersion: "12.0.0",
  version: "22.1.4",
  ngImport: i0,
  type: RouterLinkActive,
  decorators: [{
    type: Directive,
    args: [{
      selector: '[routerLinkActive]',
      exportAs: 'routerLinkActive'
    }]
  }],
  ctorParameters: () => [{
    type: Router
  }, {
    type: i0.ElementRef
  }, {
    type: i0.Renderer2
  }, {
    type: i0.ChangeDetectorRef
  }],
  propDecorators: {
    links: [{
      type: ContentChildren,
      args: [RouterLink, {
        descendants: true
      }]
    }],
    routerLinkActiveOptions: [{
      type: Input
    }],
    ariaCurrentWhenActive: [{
      type: Input
    }],
    isActiveChange: [{
      type: Output
    }],
    routerLinkActive: [{
      type: Input
    }]
  }
});
function isActiveMatchOptions(options) {
  const o = options;
  return !!(o.paths || o.matrixParams || o.queryParams || o.fragment);
}

const BLOCKING_SYMBOL = Symbol(typeof ngDevMode === 'undefined' || ngDevMode ? '__isBlocking' : '');
const SOURCE_RESOURCE_SYMBOL = Symbol(typeof ngDevMode === 'undefined' || ngDevMode ? '__sourceResource' : '');
function hasValueOrResolved(res) {
  const status = res.status();
  return res.hasValue() || status !== 'loading' && status !== 'reloading';
}
function nonBlocking(res) {
  res[BLOCKING_SYMBOL] = false;
  return res;
}
function routerResource(source) {
  ngDevMode && assertInInjectionContext(routerResource);
  const injector = inject(Injector);
  const router = injector.get(Router);
  const {
    snapshot: snapshotSignal,
    frozenSnapshot
  } = createTransactionalSnapshot(source, router, injector);
  const res = resourceFromSnapshots(snapshotSignal);
  res[SOURCE_RESOURCE_SYMBOL] = source;
  res[BLOCKING_SYMBOL] = source[BLOCKING_SYMBOL] !== false;
  if (typeof source.reload === 'function') {
    res.reload = function () {
      if (frozenSnapshot() !== null) {
        return false;
      }
      return source.reload();
    };
  } else {
    res.reload = () => false;
  }
  return res;
}
function createTransactionalSnapshot(source, router, injector) {
  const frozenSnapshot = signal(null, ...(ngDevMode ? [{
    debugName: "frozenSnapshot"
  }] : []));
  const isRollbackRecoveryPending = signal(false, ...(ngDevMode ? [{
    debugName: "isRollbackRecoveryPending"
  }] : []));
  const sub = router.events.subscribe(e => {
    if (e instanceof NavigationStart) {
      isRollbackRecoveryPending.set(false);
      if (frozenSnapshot() === null) {
        frozenSnapshot.set(source.snapshot());
      }
    } else if (e instanceof NavigationEnd) {
      frozenSnapshot.set(null);
      isRollbackRecoveryPending.set(false);
    } else if (e instanceof NavigationSkipped) {
      if (frozenSnapshot() !== null) {
        isRollbackRecoveryPending.set(true);
      }
    } else if (e instanceof NavigationCancel || e instanceof NavigationError) {
      const isRollback = e instanceof NavigationError || e instanceof NavigationCancel && e.code !== NavigationCancellationCode.SupersededByNewNavigation && e.code !== NavigationCancellationCode.Redirect;
      if (!isRollback) return;
      isRollbackRecoveryPending.set(true);
    }
  });
  injector.get(DestroyRef).onDestroy(() => sub.unsubscribe());
  effect(() => {
    if (isRollbackRecoveryPending() && hasValueOrResolved(source)) {
      isRollbackRecoveryPending.set(false);
      frozenSnapshot.set(null);
    }
  }, {
    injector
  });
  return {
    snapshot: computed(() => frozenSnapshot() ?? source.snapshot()),
    frozenSnapshot
  };
}
function createResourceOutletBindingEffects(componentRef, route, injector) {
  const createdEffects = [];
  const handledKeys = [];
  const mirror = route.component ? reflectComponentType(route.component) : null;
  if (!mirror) {
    return {
      createdEffects,
      handledKeys
    };
  }
  for (const {
    templateName
  } of mirror.inputs) {
    const resource = route.resources?.[templateName];
    if (!resource || !resource[BLOCKING_SYMBOL]) {
      continue;
    }
    const effectRef = effect(() => {
      componentRef.setInput(templateName, resource.value());
    }, {
      ...(ngDevMode ? {
        debugName: "effectRef"
      } : {}),
      injector
    });
    createdEffects.push(effectRef);
    handledKeys.push(templateName);
  }
  return {
    createdEffects,
    handledKeys
  };
}

function setupAndRunResources(abortSignal) {
  return pipe(switchTap(({
    newlyCreatedRoutes,
    targetRouterState
  }) => {
    if (!newlyCreatedRoutes || !targetRouterState || abortSignal.aborted) {
      return;
    }
    const resourceSetupPromises = [];
    const blockingResourcePromises = [];
    const traverse = stateNode => {
      const route = stateNode.value;
      if (route) {
        initializeActivatedRoute(route);
        processRoute(route, newlyCreatedRoutes, resourceSetupPromises, abortSignal, blockingResourcePromises);
      }
      for (const childState of stateNode.children) {
        traverse(childState);
      }
    };
    traverse(targetRouterState._root);
    return Promise.all(resourceSetupPromises).then(() => Promise.all(blockingResourcePromises));
  }));
}
function processRoute(route, newlyCreatedRoutes, resourceSetupPromises, abortSignal, blockingResourcePromises) {
  const resources = route.routeConfig?.resources;
  if (!resources) {
    return;
  }
  if (newlyCreatedRoutes.has(route)) {
    resourceSetupPromises.push(setupNewRouterResources(route._futureSnapshot, route, abortSignal, blockingResourcePromises));
  } else {
    updateExistingResources(route, blockingResourcePromises, abortSignal);
  }
}
async function setupNewRouterResources(snapshot, route, abortSignal, blockingResourcePromises) {
  const resourcesFn = snapshot?.routeConfig?.resources;
  const parentInjector = snapshot?._environmentInjector;
  if (!resourcesFn || !parentInjector) {
    return;
  }
  let childInjector = route._localInjector;
  if (!childInjector) {
    childInjector = createEnvironmentInjector([], parentInjector);
    route._localInjector = childInjector;
  }
  const context = {
    params: route.paramsSignal,
    queryParams: route.queryParamsSignal,
    fragment: route.fragmentSignal,
    data: route.dataSignal,
    snapshot: route._futureSnapshot
  };
  const resourceResultRaw = runInInjectionContext(childInjector, () => resourcesFn(context));
  let resourceResult;
  if (resourceResultRaw instanceof Promise) {
    resourceResult = await resourceResultRaw;
    if (abortSignal.aborted) return;
  } else {
    resourceResult = resourceResultRaw;
  }
  if (!resourceResult) return;
  const wrappedResult = {};
  for (const [key, res] of Object.entries(resourceResult)) {
    if (typeof ngDevMode === 'undefined' || ngDevMode) {
      if (!res || typeof res !== 'object' || typeof res.snapshot !== 'function') {
        throw new Error(`Invalid resource returned for key "${key}". Expected a Resource, but got ${res === null ? 'null' : typeof res}.`);
      }
    }
    wrappedResult[key] = runInInjectionContext(childInjector, () => routerResource(res));
  }
  route.resources = route._futureSnapshot.resources = snapshot.resources = wrappedResult;
  setupBlocking(route, wrappedResult, blockingResourcePromises, abortSignal);
}
function updateExistingResources(route, blockingResourcePromises, abortSignal) {
  const currentResources = route.snapshot?.resources;
  if (!currentResources) {
    return;
  }
  Object.values(currentResources).forEach(r => {
    const underlyingRes = r[SOURCE_RESOURCE_SYMBOL];
    if (underlyingRes.status() === 'error') {
      underlyingRes.reload?.();
    }
  });
  route._futureSnapshot.resources = currentResources;
  setupBlocking(route, currentResources, blockingResourcePromises, abortSignal);
}
function setupBlocking(route, resourceResult, blockingResourcePromises, abortSignal) {
  if (abortSignal.aborted) return;
  const childInjector = route._localInjector;
  if (!childInjector || !resourceResult) return;
  for (const r of Object.values(resourceResult)) {
    const res = r;
    if (res[BLOCKING_SYMBOL] === false) {
      continue;
    }
    const promise = new Promise((resolve, reject) => {
      const underlyingRes = res[SOURCE_RESOURCE_SYMBOL];
      let isDestroyed = false;
      let unregisterOnDestroy;
      const cleanup = () => {
        isDestroyed = true;
        blockingEffect.destroy();
        unregisterOnDestroy?.();
        abortSignal.removeEventListener('abort', onAbort);
      };
      const onAbort = () => {
        cleanup();
        resolve();
      };
      abortSignal.addEventListener('abort', onAbort, {
        once: true
      });
      const blockingEffect = effect(() => {
        if (isDestroyed) {
          return;
        }
        const status = underlyingRes.status();
        if (status === 'error') {
          cleanup();
          reject(underlyingRes.error());
        } else if (hasValueOrResolved(underlyingRes)) {
          cleanup();
          resolve();
        }
      }, {
        ...(ngDevMode ? {
          debugName: "blockingEffect"
        } : {}),
        injector: childInjector,
        manualCleanup: true
      });
      unregisterOnDestroy = childInjector.get(DestroyRef).onDestroy(() => {
        cleanup();
        resolve();
      });
    });
    blockingResourcePromises.push(promise);
  }
}

class PreloadingStrategy {}
class PreloadAllModules {
  preload(route, fn) {
    return fn().pipe(catchError(() => of(null)));
  }
  static ɵfac = i0.ɵɵngDeclareFactory({
    minVersion: "12.0.0",
    version: "22.1.4",
    ngImport: i0,
    type: PreloadAllModules,
    deps: [],
    target: i0.ɵɵFactoryTarget.Service
  });
  static ɵprov = i0.ɵɵngDeclareService({
    minVersion: "22.0.0",
    version: "22.1.4",
    ngImport: i0,
    type: PreloadAllModules
  });
}
i0.ɵɵngDeclareClassMetadata({
  minVersion: "12.0.0",
  version: "22.1.4",
  ngImport: i0,
  type: PreloadAllModules,
  decorators: [{
    type: Service
  }]
});
class NoPreloading {
  preload(route, fn) {
    return of(null);
  }
  static ɵfac = i0.ɵɵngDeclareFactory({
    minVersion: "12.0.0",
    version: "22.1.4",
    ngImport: i0,
    type: NoPreloading,
    deps: [],
    target: i0.ɵɵFactoryTarget.Service
  });
  static ɵprov = i0.ɵɵngDeclareService({
    minVersion: "22.0.0",
    version: "22.1.4",
    ngImport: i0,
    type: NoPreloading
  });
}
i0.ɵɵngDeclareClassMetadata({
  minVersion: "12.0.0",
  version: "22.1.4",
  ngImport: i0,
  type: NoPreloading,
  decorators: [{
    type: Service
  }]
});
class RouterPreloader {
  router;
  injector;
  preloadingStrategy;
  loader;
  subscription;
  constructor(router, injector, preloadingStrategy, loader) {
    this.router = router;
    this.injector = injector;
    this.preloadingStrategy = preloadingStrategy;
    this.loader = loader;
  }
  setUpPreloading() {
    this.subscription = this.router.events.pipe(filter(e => e instanceof NavigationEnd), concatMap(() => this.preload())).subscribe(() => {});
  }
  preload() {
    return this.processRoutes(this.injector, this.router.config);
  }
  ngOnDestroy() {
    this.subscription?.unsubscribe();
  }
  processRoutes(injector, routes) {
    const res = [];
    for (const route of routes) {
      if (route.providers && !route._injector) {
        route._injector = createEnvironmentInjector(route.providers, injector, typeof ngDevMode === 'undefined' || ngDevMode ? `Route: ${route.path}` : '');
      }
      const injectorForCurrentRoute = route._injector ?? injector;
      if (route._loadedNgModuleFactory && !route._loadedInjector) {
        route._loadedInjector = route._loadedNgModuleFactory.create(injectorForCurrentRoute).injector;
      }
      const injectorForChildren = route._loadedInjector ?? injectorForCurrentRoute;
      if (route.loadChildren && !route._loadedRoutes && route.canLoad === undefined || route.loadComponent && !route._loadedComponent) {
        res.push(this.preloadConfig(injectorForCurrentRoute, route));
      }
      if (route.children || route._loadedRoutes) {
        res.push(this.processRoutes(injectorForChildren, route.children ?? route._loadedRoutes));
      }
    }
    return from(res).pipe(mergeAll());
  }
  preloadConfig(injector, route) {
    return this.preloadingStrategy.preload(route, () => {
      if (injector.destroyed) {
        return of(null);
      }
      let loadedChildren$;
      if (route.loadChildren && route.canLoad === undefined) {
        loadedChildren$ = from(this.loader.loadChildren(injector, route));
      } else {
        loadedChildren$ = of(null);
      }
      const recursiveLoadChildren$ = loadedChildren$.pipe(mergeMap(config => {
        if (config === null) {
          return of(void 0);
        }
        route._loadedRoutes = config.routes;
        route._loadedInjector = config.injector;
        route._loadedNgModuleFactory = config.factory;
        return this.processRoutes(config.injector ?? injector, config.routes);
      }));
      if (route.loadComponent && !route._loadedComponent) {
        const loadComponent$ = this.loader.loadComponent(injector, route);
        return from([recursiveLoadChildren$, loadComponent$]).pipe(mergeAll());
      } else {
        return recursiveLoadChildren$;
      }
    });
  }
  static ɵfac = i0.ɵɵngDeclareFactory({
    minVersion: "12.0.0",
    version: "22.1.4",
    ngImport: i0,
    type: RouterPreloader,
    deps: [{
      token: Router
    }, {
      token: i0.EnvironmentInjector
    }, {
      token: PreloadingStrategy
    }, {
      token: RouterConfigLoader
    }],
    target: i0.ɵɵFactoryTarget.Injectable
  });
  static ɵprov = i0.ɵɵngDeclareInjectable({
    minVersion: "12.0.0",
    version: "22.1.4",
    ngImport: i0,
    type: RouterPreloader,
    providedIn: 'root'
  });
}
i0.ɵɵngDeclareClassMetadata({
  minVersion: "12.0.0",
  version: "22.1.4",
  ngImport: i0,
  type: RouterPreloader,
  decorators: [{
    type: Injectable,
    args: [{
      providedIn: 'root'
    }]
  }],
  ctorParameters: () => [{
    type: Router
  }, {
    type: i0.EnvironmentInjector
  }, {
    type: PreloadingStrategy
  }, {
    type: RouterConfigLoader
  }]
});

const ROUTER_SCROLLER = new InjectionToken(typeof ngDevMode !== 'undefined' && ngDevMode ? 'Router Scroller' : '');
class RouterScroller {
  options;
  routerEventsSubscription;
  scrollEventsSubscription;
  lastId = 0;
  lastSource = IMPERATIVE_NAVIGATION;
  restoredId = 0;
  store = {};
  isHydrating = inject(_IS_HYDRATION_DOM_REUSE_ENABLED, {
    optional: true
  }) ?? false;
  urlSerializer = inject(UrlSerializer);
  zone = inject(NgZone);
  viewportScroller = inject(ViewportScroller);
  transitions = inject(NavigationTransitions);
  constructor(options) {
    this.options = options;
    this.options.scrollPositionRestoration ||= 'disabled';
    this.options.anchorScrolling ||= 'disabled';
    if (this.isHydrating) {
      inject(ApplicationRef).whenStable().then(() => {
        this.isHydrating = false;
      });
    }
  }
  init() {
    if (this.options.scrollPositionRestoration !== 'disabled') {
      this.viewportScroller.setHistoryScrollRestoration('manual');
    }
    this.routerEventsSubscription = this.createScrollEvents();
    this.scrollEventsSubscription = this.consumeScrollEvents();
  }
  createScrollEvents() {
    return this.transitions.events.subscribe(e => {
      if (e instanceof NavigationStart) {
        this.store[this.lastId] = this.viewportScroller.getScrollPosition();
        this.lastSource = e.navigationTrigger;
        this.restoredId = e.restoredState ? e.restoredState.navigationId : 0;
      } else if (e instanceof NavigationEnd) {
        this.lastId = e.id;
        this.scheduleScrollEvent(e, this.urlSerializer.parse(e.urlAfterRedirects).fragment);
      } else if (e instanceof NavigationSkipped && e.code === NavigationSkippedCode.IgnoredSameUrlNavigation) {
        this.lastSource = undefined;
        this.restoredId = 0;
        this.scheduleScrollEvent(e, this.urlSerializer.parse(e.url).fragment);
      }
    });
  }
  consumeScrollEvents() {
    return this.transitions.events.subscribe(e => {
      if (!(e instanceof Scroll) || e.scrollBehavior === 'manual') return;
      const instantScroll = {
        behavior: 'instant'
      };
      if (e.position) {
        if (this.options.scrollPositionRestoration === 'top') {
          this.viewportScroller.scrollToPosition([0, 0], instantScroll);
        } else if (this.options.scrollPositionRestoration === 'enabled') {
          this.viewportScroller.scrollToPosition(e.position, instantScroll);
        }
      } else {
        if (e.anchor && this.options.anchorScrolling === 'enabled') {
          this.viewportScroller.scrollToAnchor(e.anchor);
        } else if (this.options.scrollPositionRestoration !== 'disabled') {
          this.viewportScroller.scrollToPosition([0, 0]);
        }
      }
    });
  }
  scheduleScrollEvent(routerEvent, anchor) {
    if (this.isHydrating) return;
    const scroll = untracked(this.transitions.currentNavigation)?.extras.scroll;
    this.zone.runOutsideAngular(async () => {
      await new Promise(resolve => {
        setTimeout(resolve);
        if (typeof requestAnimationFrame !== 'undefined') {
          requestAnimationFrame(resolve);
        }
      });
      this.zone.run(() => {
        this.transitions.events.next(new Scroll(routerEvent, this.lastSource === 'popstate' ? this.store[this.restoredId] : null, anchor, scroll));
      });
    });
  }
  ngOnDestroy() {
    this.routerEventsSubscription?.unsubscribe();
    this.scrollEventsSubscription?.unsubscribe();
  }
  static ɵfac = i0.ɵɵngDeclareFactory({
    minVersion: "12.0.0",
    version: "22.1.4",
    ngImport: i0,
    type: RouterScroller,
    deps: "invalid",
    target: i0.ɵɵFactoryTarget.Injectable
  });
  static ɵprov = i0.ɵɵngDeclareInjectable({
    minVersion: "12.0.0",
    version: "22.1.4",
    ngImport: i0,
    type: RouterScroller
  });
}
i0.ɵɵngDeclareClassMetadata({
  minVersion: "12.0.0",
  version: "22.1.4",
  ngImport: i0,
  type: RouterScroller,
  decorators: [{
    type: Injectable
  }],
  ctorParameters: () => [{
    type: undefined
  }]
});

function getLoadedRoutes(route) {
  return route._loadedRoutes;
}
function getRouterInstance(injector) {
  return injector.get(Router, null, {
    optional: true
  });
}
function navigateByUrl(router, url) {
  if (!(router instanceof Router)) {
    throw new Error('The provided router is not an Angular Router.');
  }
  return router.navigateByUrl(url);
}

class NavigationStateManager extends StateManager {
  injector = inject(EnvironmentInjector);
  navigation = inject(PlatformNavigation);
  inMemoryScrollingEnabled = inject(ROUTER_SCROLLER, {
    optional: true
  }) !== null;
  base = new URL(inject(PlatformLocation).href).origin;
  appRootUrl = new URL(this.location.prepareExternalUrl?.('/') ?? '/', this.base);
  precommitHandlerSupported = inject(_PRECOMMIT_HANDLER_SUPPORTED);
  activeHistoryEntry = this.navigation.currentEntry;
  currentNavigation = {};
  nonRouterCurrentEntryChangeSubject = new Subject();
  nonRouterEntryChangeListener;
  get registered() {
    return this.nonRouterEntryChangeListener !== undefined && !this.nonRouterEntryChangeListener.closed;
  }
  constructor() {
    super();
    const navigateListener = event => {
      this.handleNavigate(event);
    };
    this.navigation.addEventListener('navigate', navigateListener);
    inject(DestroyRef).onDestroy(() => this.navigation.removeEventListener('navigate', navigateListener));
  }
  registerNonRouterCurrentEntryChangeListener(listener) {
    this.activeHistoryEntry = this.navigation.currentEntry;
    this.nonRouterEntryChangeListener = this.nonRouterCurrentEntryChangeSubject.subscribe(({
      path,
      state
    }) => {
      listener(path, state, 'popstate', !this.precommitHandlerSupported ? {
        replaceUrl: true
      } : {});
    });
    return this.nonRouterEntryChangeListener;
  }
  async handleRouterEvent(e, transition) {
    this.currentNavigation = {
      ...this.currentNavigation,
      routerTransition: transition
    };
    if (e instanceof NavigationStart) {
      this.updateStateMemento();
      if (this.precommitHandlerSupported) {
        this.maybeCreateNavigationForTransition(transition);
      }
    } else if (e instanceof NavigationSkipped) {
      this.finishNavigation();
      this.commitTransition(transition);
    } else if (e instanceof BeforeRoutesRecognized) {
      transition.routesRecognizeHandler.deferredHandle = new Promise(async resolve => {
        if (this.urlUpdateStrategy === 'eager') {
          try {
            this.maybeCreateNavigationForTransition(transition);
            await this.currentNavigation.commitUrl?.();
          } catch {
            return;
          }
        }
        resolve();
      });
    } else if (e instanceof BeforeActivateRoutes) {
      transition.beforeActivateHandler.deferredHandle = new Promise(async resolve => {
        if (this.urlUpdateStrategy === 'deferred') {
          try {
            this.maybeCreateNavigationForTransition(transition);
            await this.currentNavigation.commitUrl?.();
          } catch {
            return;
          }
        }
        this.commitTransition(transition);
        resolve();
      });
    } else if (e instanceof NavigationCancel || e instanceof NavigationError) {
      const redirectingBeforeUrlCommit = e instanceof NavigationCancel && e.code === NavigationCancellationCode.Redirect && !!this.currentNavigation.commitUrl;
      if (redirectingBeforeUrlCommit) {
        return;
      }
      void this.cancel(transition, e);
    } else if (e instanceof NavigationEnd) {
      const {
        resolveHandler,
        removeAbortListener
      } = this.currentNavigation;
      this.currentNavigation = {};
      removeAbortListener?.();
      this.activeHistoryEntry = this.navigation.currentEntry;
      afterNextRender({
        read: () => resolveHandler?.()
      }, {
        injector: this.injector
      });
    }
  }
  maybeCreateNavigationForTransition(transition) {
    const {
      navigationEvent,
      commitUrl
    } = this.currentNavigation;
    if (commitUrl || navigationEvent && navigationEvent.navigationType === 'traverse' && this.eventAndRouterDestinationsMatch(navigationEvent, transition)) {
      return;
    }
    this.currentNavigation.removeAbortListener?.();
    const path = this.createBrowserPath(transition);
    this.navigate(path, transition);
  }
  navigate(internalPath, transition) {
    const path = transition.extras.skipLocationChange ? this.navigation.currentEntry.url : this.location.prepareExternalUrl(internalPath);
    const state = {
      ...transition.extras.state,
      ...this.generateNgRouterState(transition)
    };
    const info = {
      ɵrouterInfo: {
        intercept: true
      }
    };
    if (!this.navigation.transition && this.currentNavigation.navigationEvent) {
      transition.extras.replaceUrl = false;
    }
    const history = this.location.isCurrentPathEqualTo(path) || transition.extras.replaceUrl || transition.extras.skipLocationChange ? 'replace' : 'push';
    handleResultRejections(this.navigation.navigate(path, {
      state,
      history,
      info
    }));
  }
  finishNavigation() {
    this.currentNavigation.commitUrl?.();
    this.currentNavigation?.resolveHandler?.();
    this.currentNavigation = {};
  }
  async cancel(transition, cause) {
    this.currentNavigation.rejectNavigateEvent?.();
    const clearedState = {};
    this.currentNavigation = clearedState;
    if (isRedirectingEvent(cause)) {
      return;
    }
    const isTraversalReset = this.canceledNavigationResolution === 'computed' && this.navigation.currentEntry.key !== this.activeHistoryEntry.key;
    this.resetInternalState(transition.finalUrl, isTraversalReset);
    if (this.navigation.currentEntry.id === this.activeHistoryEntry.id) {
      return;
    }
    if (cause instanceof NavigationCancel && cause.code === NavigationCancellationCode.Aborted) {
      await Promise.resolve();
      if (this.currentNavigation !== clearedState) {
        return;
      }
    }
    if (isTraversalReset) {
      handleResultRejections(this.navigation.traverseTo(this.activeHistoryEntry.key, {
        info: {
          ɵrouterInfo: {
            intercept: false
          }
        }
      }));
    } else {
      const internalPath = this.urlSerializer.serialize(this.getCurrentUrlTree());
      const pathOrUrl = this.location.prepareExternalUrl(internalPath);
      handleResultRejections(this.navigation.navigate(pathOrUrl, {
        state: this.activeHistoryEntry.getState(),
        history: 'replace',
        info: {
          ɵrouterInfo: {
            intercept: false
          }
        }
      }));
    }
  }
  resetInternalState(finalUrl, traversalReset) {
    this.routerState = this.stateMemento.routerState;
    this.currentUrlTree = this.stateMemento.currentUrlTree;
    this.rawUrlTree = traversalReset ? this.stateMemento.rawUrlTree : this.urlHandlingStrategy.merge(this.currentUrlTree, finalUrl ?? this.rawUrlTree);
  }
  handleNavigate(event) {
    if (!event.canIntercept || event.navigationType === 'reload') {
      return;
    }
    const routerInfo = event?.info?.ɵrouterInfo;
    if (routerInfo && !routerInfo.intercept) {
      return;
    }
    const isTriggeredByRouterTransition = !!routerInfo;
    if (!isTriggeredByRouterTransition) {
      const {
        pathname: destPathname,
        origin: destOrigin
      } = new URL(event.destination.url);
      const {
        pathname: rootPathname,
        origin: appOrigin
      } = this.appRootUrl;
      const rootPath = rootPathname.endsWith('/') ? rootPathname : rootPathname + '/';
      if (destOrigin !== appOrigin || destPathname !== rootPathname && !destPathname.startsWith(rootPath)) {
        return;
      }
      this.currentNavigation.routerTransition?.abort();
      if (!this.registered) {
        this.finishNavigation();
        return;
      }
    }
    this.currentNavigation = {
      ...this.currentNavigation
    };
    this.currentNavigation.navigationEvent = event;
    const abortHandler = () => {
      this.currentNavigation.routerTransition?.abort();
    };
    event.signal.addEventListener('abort', abortHandler);
    this.currentNavigation.removeAbortListener = () => event.signal.removeEventListener('abort', abortHandler);
    let scroll = this.inMemoryScrollingEnabled ? 'manual' : this.currentNavigation.routerTransition?.extras.scroll ?? 'after-transition';
    const interceptOptions = {
      scroll
    };
    const {
      promise: handlerPromise,
      resolve: resolveHandler,
      reject: rejectHandler
    } = _promiseWithResolvers();
    const {
      promise: precommitHandlerPromise,
      resolve: resolvePrecommitHandler,
      reject: rejectPrecommitHandler
    } = _promiseWithResolvers();
    this.currentNavigation.rejectNavigateEvent = () => {
      event.signal.removeEventListener('abort', abortHandler);
      rejectPrecommitHandler();
      rejectHandler();
    };
    this.currentNavigation.resolveHandler = () => {
      this.currentNavigation.removeAbortListener?.();
      resolveHandler();
    };
    handlerPromise.catch(() => {});
    precommitHandlerPromise.catch(() => {});
    interceptOptions.handler = () => handlerPromise;
    if (this.deferredCommitSupported(event)) {
      const redirect = new Promise(resolve => {
        interceptOptions.precommitHandler = controller => {
          if (this.navigation.transition?.navigationType === 'traverse') {
            resolve(() => {});
          } else {
            resolve(controller.redirect.bind(controller));
          }
          return precommitHandlerPromise;
        };
      });
      this.currentNavigation.commitUrl = async () => {
        this.currentNavigation.commitUrl = undefined;
        const transition = this.currentNavigation.routerTransition;
        if (transition && !transition.extras.skipLocationChange) {
          const internalPath = this.createBrowserPath(transition);
          const history = this.location.isCurrentPathEqualTo(internalPath) || !!transition.extras.replaceUrl ? 'replace' : 'push';
          const state = {
            ...transition.extras.state,
            ...this.generateNgRouterState(transition)
          };
          const pathOrUrl = this.location.prepareExternalUrl(internalPath);
          (await redirect)(pathOrUrl, {
            state,
            history
          });
        }
        resolvePrecommitHandler();
        return await this.navigation.transition?.committed;
      };
    }
    event.intercept(interceptOptions);
    if (!isTriggeredByRouterTransition) {
      this.handleNavigateEventTriggeredOutsideRouterAPIs(event);
    }
  }
  handleNavigateEventTriggeredOutsideRouterAPIs(event) {
    const path = event.destination.url.substring(this.appRootUrl.href.length - 1);
    const state = event.destination.getState();
    this.nonRouterCurrentEntryChangeSubject.next({
      path,
      state
    });
  }
  eventAndRouterDestinationsMatch(navigateEvent, transition) {
    const internalPath = this.createBrowserPath(transition);
    const eventDestination = new URL(navigateEvent.destination.url);
    const routerDestination = new URL(this.location.prepareExternalUrl(internalPath), eventDestination.origin);
    eventDestination.searchParams.sort();
    routerDestination.searchParams.sort();
    const {
      pathname: destPathname,
      search: destSearch,
      hash: hashDest
    } = routerDestination;
    const {
      pathname: eventDestPathname,
      search: eventDestSearch,
      hash: eventDestHash
    } = eventDestination;
    return destSearch === eventDestSearch && hashDest === eventDestHash && Location.stripTrailingSlash(destPathname) === Location.stripTrailingSlash(eventDestPathname);
  }
  generateNgRouterState(transition) {
    return {
      ...this.routerUrlState(transition),
      navigationId: transition.id
    };
  }
  deferredCommitSupported(event) {
    return this.precommitHandlerSupported && event.cancelable;
  }
  static ɵfac = i0.ɵɵngDeclareFactory({
    minVersion: "12.0.0",
    version: "22.1.4",
    ngImport: i0,
    type: NavigationStateManager,
    deps: [],
    target: i0.ɵɵFactoryTarget.Service
  });
  static ɵprov = i0.ɵɵngDeclareService({
    minVersion: "22.0.0",
    version: "22.1.4",
    ngImport: i0,
    type: NavigationStateManager
  });
}
i0.ɵɵngDeclareClassMetadata({
  minVersion: "12.0.0",
  version: "22.1.4",
  ngImport: i0,
  type: NavigationStateManager,
  decorators: [{
    type: Service
  }],
  ctorParameters: () => []
});
function handleResultRejections(result) {
  result.finished?.catch(() => {});
  result.committed?.catch(() => {});
  return result;
}

function provideRouter(routes, ...features) {
  if (typeof ngDevMode === 'undefined' || ngDevMode) {
    _publishNonCoreGlobalUtil('ɵgetLoadedRoutes', getLoadedRoutes);
    _publishNonCoreGlobalUtil('ɵgetRouterInstance', getRouterInstance);
    _publishNonCoreGlobalUtil('ɵnavigateByUrl', navigateByUrl);
  }
  return makeEnvironmentProviders([{
    provide: ROUTES,
    multi: true,
    useValue: routes
  }, {
    provide: ActivatedRoute,
    useFactory: rootRoute
  }, {
    provide: APP_BOOTSTRAP_LISTENER,
    multi: true,
    useFactory: getBootstrapListener
  }, features.map(feature => feature.ɵproviders)]);
}
function rootRoute() {
  return inject(Router).routerState.root;
}
function routerFeature(kind, providers) {
  return {
    ɵkind: kind,
    ɵproviders: providers
  };
}
function withInMemoryScrolling(options = {}) {
  const providers = [{
    provide: ROUTER_SCROLLER,
    useFactory: () => new RouterScroller(options)
  }];
  return routerFeature(4, providers);
}
function withExperimentalPlatformNavigation() {
  const devModeLocationCheck = typeof ngDevMode === 'undefined' || ngDevMode ? [provideEnvironmentInitializer(() => {
    const locationInstance = inject(Location);
    if (!(locationInstance instanceof _NavigationAdapterForLocation)) {
      const locationConstructorName = locationInstance.constructor.name;
      let message = `'withExperimentalPlatformNavigation' provides a 'Location' implementation that ensures navigation APIs are consistently used.` + ` An instance of ${locationConstructorName} was found instead.`;
      if (locationConstructorName === 'SpyLocation') {
        message += ` One of 'RouterTestingModule' or 'provideLocationMocks' was likely used. 'withExperimentalPlatformNavigation' does not work with these because they override the Location implementation.`;
      }
      throw new Error(message);
    }
  })] : [];
  const providers = [{
    provide: StateManager,
    useExisting: NavigationStateManager
  }, {
    provide: Location,
    useClass: _NavigationAdapterForLocation
  }, devModeLocationCheck];
  return routerFeature(11, providers);
}
function getBootstrapListener() {
  const injector = inject(Injector);
  return bootstrappedComponentRef => {
    const ref = injector.get(ApplicationRef);
    if (bootstrappedComponentRef !== ref.components[0]) {
      return;
    }
    const router = injector.get(Router);
    const bootstrapDone = injector.get(BOOTSTRAP_DONE);
    if (injector.get(INITIAL_NAVIGATION) === 1) {
      router.initialNavigation();
    }
    injector.get(ROUTER_PRELOADER, null, {
      optional: true
    })?.setUpPreloading();
    injector.get(ROUTER_SCROLLER, null, {
      optional: true
    })?.init();
    router.resetRootComponentType(ref.componentTypes[0]);
    if (!bootstrapDone.closed) {
      bootstrapDone.next();
      bootstrapDone.complete();
      bootstrapDone.unsubscribe();
    }
  };
}
const BOOTSTRAP_DONE = new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'bootstrap done indicator' : '', {
  factory: () => {
    return new Subject();
  }
});
const INITIAL_NAVIGATION = new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'initial navigation' : '', {
  factory: () => 1
});
function withEnabledBlockingInitialNavigation() {
  const providers = [{
    provide: _IS_ENABLED_BLOCKING_INITIAL_NAVIGATION,
    useValue: true
  }, {
    provide: INITIAL_NAVIGATION,
    useValue: 0
  }, provideAppInitializer(() => {
    const injector = inject(Injector);
    const locationInitialized = injector.get(LOCATION_INITIALIZED, Promise.resolve());
    return locationInitialized.then(() => {
      return new Promise(resolve => {
        const router = injector.get(Router);
        const bootstrapDone = injector.get(BOOTSTRAP_DONE);
        afterNextNavigation(router, () => {
          resolve(true);
        });
        injector.get(NavigationTransitions).afterPreactivation = () => {
          resolve(true);
          return bootstrapDone.closed ? of(void 0) : bootstrapDone;
        };
        router.initialNavigation();
      });
    });
  })];
  return routerFeature(2, providers);
}
function withDisabledInitialNavigation() {
  const providers = [provideAppInitializer(() => {
    inject(Router).setUpLocationChangeListener();
  }), {
    provide: INITIAL_NAVIGATION,
    useValue: 2
  }];
  return routerFeature(3, providers);
}
function withDebugTracing() {
  let providers = [];
  if (typeof ngDevMode === 'undefined' || ngDevMode) {
    providers = [{
      provide: ENVIRONMENT_INITIALIZER,
      multi: true,
      useFactory: () => {
        const router = inject(Router);
        return () => router.events.subscribe(e => {
          console.group?.(`Router Event: ${e.constructor.name}`);
          console.log(stringifyEvent(e));
          console.log(e);
          console.groupEnd?.();
        });
      }
    }];
  } else {
    providers = [];
  }
  return routerFeature(1, providers);
}
const ROUTER_PRELOADER = new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'router preloader' : '');
function withPreloading(preloadingStrategy) {
  const providers = [{
    provide: ROUTER_PRELOADER,
    useExisting: RouterPreloader
  }, {
    provide: PreloadingStrategy,
    useExisting: preloadingStrategy
  }];
  return routerFeature(0, providers);
}
function withRouterConfig(options) {
  const providers = [{
    provide: ROUTER_CONFIGURATION,
    useValue: options
  }];
  return routerFeature(5, providers);
}
function withHashLocation() {
  const providers = [{
    provide: LocationStrategy,
    useClass: HashLocationStrategy
  }];
  return routerFeature(6, providers);
}
function withNavigationErrorHandler(handler) {
  const providers = [{
    provide: NAVIGATION_ERROR_HANDLER,
    useValue: handler
  }];
  return routerFeature(7, providers);
}
function withExperimentalAutoCleanupInjectors() {
  return routerFeature(10, [{
    provide: ROUTE_INJECTOR_CLEANUP,
    useValue: routeInjectorCleanup
  }]);
}
function withComponentInputBinding(options = {}) {
  const providers = [{
    provide: INPUT_BINDER,
    useFactory: () => new RoutedComponentInputBinder(options, inject(ROUTER_RESOURCES_FEATURE, {
      optional: true
    }))
  }];
  return routerFeature(8, providers);
}
function withViewTransitions(options) {
  _performanceMarkFeature('NgRouterViewTransitions');
  const providers = [{
    provide: CREATE_VIEW_TRANSITION,
    useValue: createViewTransition
  }, {
    provide: VIEW_TRANSITION_OPTIONS,
    useValue: {
      skipNextTransition: !!options?.skipInitialTransition,
      ...options
    }
  }];
  return routerFeature(9, providers);
}
function withRouterResources() {
  const providers = [{
    provide: ROUTER_RESOURCES_FEATURE,
    useValue: {
      setupAndRunResources,
      createResourceOutletBindingEffects
    }
  }];
  return routerFeature(9, providers);
}

const ROUTER_DIRECTIVES = [RouterOutlet, RouterLink, RouterLinkActive, _EmptyOutletComponent];
const ROUTER_FORROOT_GUARD = new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'router duplicate forRoot guard' : '');
const ROUTER_PROVIDERS = [Location, {
  provide: UrlSerializer,
  useClass: DefaultUrlSerializer
}, Router, ChildrenOutletContexts, {
  provide: ActivatedRoute,
  useFactory: rootRoute
}, RouterConfigLoader];
class RouterModule {
  constructor() {
    if (typeof ngDevMode === 'undefined' || ngDevMode) {
      inject(ROUTER_FORROOT_GUARD, {
        optional: true
      });
    }
  }
  static forRoot(routes, config) {
    return {
      ngModule: RouterModule,
      providers: [ROUTER_PROVIDERS, typeof ngDevMode === 'undefined' || ngDevMode ? config?.enableTracing ? withDebugTracing().ɵproviders : [] : [], {
        provide: ROUTES,
        multi: true,
        useValue: routes
      }, typeof ngDevMode === 'undefined' || ngDevMode ? {
        provide: ROUTER_FORROOT_GUARD,
        useFactory: provideForRootGuard
      } : [], config?.errorHandler ? {
        provide: NAVIGATION_ERROR_HANDLER,
        useValue: config.errorHandler
      } : [], {
        provide: ROUTER_CONFIGURATION,
        useValue: config ? config : {}
      }, config?.useHash ? provideHashLocationStrategy() : providePathLocationStrategy(), provideRouterScroller(), config?.preloadingStrategy ? withPreloading(config.preloadingStrategy).ɵproviders : [], config?.initialNavigation ? provideInitialNavigation(config) : [], config?.bindToComponentInputs ? withComponentInputBinding(typeof config.bindToComponentInputs === 'object' ? config.bindToComponentInputs : {}).ɵproviders : [], config?.enableViewTransitions ? withViewTransitions().ɵproviders : [], provideRouterInitializer()]
    };
  }
  static forChild(routes) {
    return {
      ngModule: RouterModule,
      providers: [{
        provide: ROUTES,
        multi: true,
        useValue: routes
      }]
    };
  }
  static ɵfac = i0.ɵɵngDeclareFactory({
    minVersion: "12.0.0",
    version: "22.1.4",
    ngImport: i0,
    type: RouterModule,
    deps: [],
    target: i0.ɵɵFactoryTarget.NgModule
  });
  static ɵmod = i0.ɵɵngDeclareNgModule({
    minVersion: "14.0.0",
    version: "22.1.4",
    ngImport: i0,
    type: RouterModule,
    imports: [RouterOutlet, RouterLink, RouterLinkActive, _EmptyOutletComponent],
    exports: [RouterOutlet, RouterLink, RouterLinkActive, _EmptyOutletComponent]
  });
  static ɵinj = i0.ɵɵngDeclareInjector({
    minVersion: "12.0.0",
    version: "22.1.4",
    ngImport: i0,
    type: RouterModule
  });
}
i0.ɵɵngDeclareClassMetadata({
  minVersion: "12.0.0",
  version: "22.1.4",
  ngImport: i0,
  type: RouterModule,
  decorators: [{
    type: NgModule,
    args: [{
      imports: ROUTER_DIRECTIVES,
      exports: ROUTER_DIRECTIVES
    }]
  }],
  ctorParameters: () => []
});
function provideRouterScroller() {
  return {
    provide: ROUTER_SCROLLER,
    useFactory: () => {
      const viewportScroller = inject(ViewportScroller);
      const config = inject(ROUTER_CONFIGURATION);
      if (config.scrollOffset) {
        viewportScroller.setOffset(config.scrollOffset);
      }
      return new RouterScroller(config);
    }
  };
}
function provideHashLocationStrategy() {
  return {
    provide: LocationStrategy,
    useClass: HashLocationStrategy
  };
}
function providePathLocationStrategy() {
  return {
    provide: LocationStrategy,
    useClass: PathLocationStrategy
  };
}
function provideForRootGuard() {
  const router = inject(Router, {
    optional: true,
    skipSelf: true
  });
  if (router) {
    throw new _RuntimeError(4007, `The Router was provided more than once. This can happen if 'forRoot' is used outside of the root injector.` + ` Lazy loaded modules should use RouterModule.forChild() instead.`);
  }
  return 'guarded';
}
function provideInitialNavigation(config) {
  return [config.initialNavigation === 'disabled' ? withDisabledInitialNavigation().ɵproviders : [], config.initialNavigation === 'enabledBlocking' ? withEnabledBlockingInitialNavigation().ɵproviders : []];
}
const ROUTER_INITIALIZER = new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'Router Initializer' : '');
function provideRouterInitializer() {
  return [{
    provide: ROUTER_INITIALIZER,
    useFactory: getBootstrapListener
  }, {
    provide: APP_BOOTSTRAP_LISTENER,
    multi: true,
    useExisting: ROUTER_INITIALIZER
  }];
}

export { NoPreloading, PreloadAllModules, PreloadingStrategy, ROUTER_INITIALIZER, ROUTER_PROVIDERS, RouterLink, RouterLinkActive, RouterModule, RouterPreloader, nonBlocking, provideRouter, withComponentInputBinding, withDebugTracing, withDisabledInitialNavigation, withEnabledBlockingInitialNavigation, withExperimentalAutoCleanupInjectors, withExperimentalPlatformNavigation, withHashLocation, withInMemoryScrolling, withNavigationErrorHandler, withPreloading, withRouterConfig, withRouterResources, withViewTransitions };
//# sourceMappingURL=_router_module-chunk.mjs.map