@real-router/angular 0.11.1 → 0.11.3

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.
Files changed (38) hide show
  1. package/dist/fesm2022/real-router-angular-ssr.mjs +9 -9
  2. package/dist/fesm2022/real-router-angular.mjs +28 -27
  3. package/dist/fesm2022/real-router-angular.mjs.map +1 -1
  4. package/package.json +10 -11
  5. package/src/components/NavigationAnnouncer.ts +0 -18
  6. package/src/components/RouteView.ts +0 -141
  7. package/src/components/RouterErrorBoundary.ts +0 -72
  8. package/src/directives/RealLink.ts +0 -144
  9. package/src/directives/RealLinkActive.ts +0 -77
  10. package/src/directives/RouteMatch.ts +0 -7
  11. package/src/directives/RouteNotFound.ts +0 -6
  12. package/src/directives/RouteSelf.ts +0 -6
  13. package/src/dom-utils/direction-tracker.ts +0 -70
  14. package/src/dom-utils/index.ts +0 -31
  15. package/src/dom-utils/link-utils.ts +0 -339
  16. package/src/dom-utils/route-announcer.ts +0 -215
  17. package/src/dom-utils/scroll-restore.ts +0 -511
  18. package/src/dom-utils/scroll-spy.ts +0 -688
  19. package/src/dom-utils/view-transitions.ts +0 -142
  20. package/src/functions/index.ts +0 -29
  21. package/src/functions/injectIsActiveRoute.ts +0 -31
  22. package/src/functions/injectNavigator.ts +0 -12
  23. package/src/functions/injectOrThrow.ts +0 -19
  24. package/src/functions/injectRoute.ts +0 -39
  25. package/src/functions/injectRouteEnter.ts +0 -117
  26. package/src/functions/injectRouteExit.ts +0 -118
  27. package/src/functions/injectRouteNode.ts +0 -19
  28. package/src/functions/injectRouteUtils.ts +0 -15
  29. package/src/functions/injectRouter.ts +0 -12
  30. package/src/functions/injectRouterTransition.ts +0 -17
  31. package/src/index.ts +0 -63
  32. package/src/internal/buildActiveRouteOptions.ts +0 -20
  33. package/src/internal/install.ts +0 -90
  34. package/src/internal/subscribeSourceToSignal.ts +0 -48
  35. package/src/providers.ts +0 -80
  36. package/src/providersFactory.ts +0 -316
  37. package/src/sourceToSignal.ts +0 -28
  38. package/src/types.ts +0 -13
@@ -1,142 +0,0 @@
1
- import type { Router } from "@real-router/core";
2
-
3
- export interface ViewTransitions {
4
- destroy: () => void;
5
- }
6
-
7
- const NOOP_INSTANCE: ViewTransitions = Object.freeze({
8
- destroy: () => {
9
- /* no-op */
10
- },
11
- });
12
-
13
- export function createViewTransitions(router: Router): ViewTransitions {
14
- if (
15
- typeof document === "undefined" ||
16
- typeof document.startViewTransition !== "function"
17
- ) {
18
- return NOOP_INSTANCE;
19
- }
20
-
21
- let closeVT: (() => void) | null = null;
22
- let currentVT: { skipTransition?: () => void } | null = null;
23
- // Tracks whether TRANSITION_SUCCESS fired for the current leave. Used to
24
- // distinguish "benign cleanup abort" (router's async path aborts its own
25
- // controller in a finally block after successful navigation) from "real
26
- // cancellation" (concurrent navigate, guard rejection, dispose).
27
- let successFired = false;
28
-
29
- const resolveAndClear = (): void => {
30
- closeVT?.();
31
- closeVT = null;
32
- };
33
-
34
- const offLeave = router.subscribeLeave(({ signal }) => {
35
- // Reentrant abort: signal already aborted when we're called. Open no VT
36
- // — router will fall through to TRANSITION_CANCELLED via isCurrentNav()
37
- // after leave resolves. addEventListener("abort", ...) does not re-fire
38
- // for past events, so skipping startViewTransition is the safe path.
39
- if (signal.aborted) {
40
- return;
41
- }
42
-
43
- successFired = false;
44
- resolveAndClear();
45
-
46
- // Return a Promise so the router awaits until the browser invokes
47
- // updateCallback. This ensures old DOM snapshot is captured BEFORE the
48
- // router commits the new state — giving correct exit→state→entry
49
- // ordering (vs fire-and-forget, where URL changes before VT captures).
50
- return new Promise<void>((resolveLeave) => {
51
- // Capture the resolver synchronously BEFORE startViewTransition() is
52
- // called. The browser invokes updateCallback in a later task, but
53
- // router.subscribe (TRANSITION_SUCCESS) can fire before that. If we
54
- // captured `resolve` inside the callback, subscribe would see closeVT
55
- // still null and skip resolving — the deferred would hang for 4s
56
- // until the VT API aborts with TimeoutError.
57
- const deferred = new Promise<void>((resolve) => {
58
- closeVT = resolve;
59
- });
60
-
61
- signal.addEventListener(
62
- "abort",
63
- () => {
64
- if (successFired) {
65
- // Router's async path (#finishAsyncNavigation) aborts its own
66
- // controller in a finally block AFTER completeTransition (and
67
- // thus AFTER subscribe fired). This is cleanup, not
68
- // cancellation — VT is progressing normally, do nothing.
69
- return;
70
- }
71
-
72
- // Real cancellation (concurrent navigate, dispose). Resolve the
73
- // deferred so updateCallback can complete, skip the VT so no
74
- // stale animation leaks, and unblock the router if the abort
75
- // fires before updateCallback was invoked.
76
- resolveAndClear();
77
- currentVT?.skipTransition?.();
78
- resolveLeave();
79
- },
80
- { once: true },
81
- );
82
-
83
- try {
84
- currentVT = document.startViewTransition(() => {
85
- // Resolving here unblocks the router at the moment the browser
86
- // enters updateCallback — by spec, old DOM snapshot is captured
87
- // before this callback runs. Router now proceeds through
88
- // activation guards and setState; the VT animation waits on
89
- // `deferred`, which is resolved from router.subscribe after a
90
- // task-queue tick (see NOTE on setTimeout below).
91
- resolveLeave();
92
-
93
- return deferred;
94
- });
95
- } catch {
96
- // Defensive: spec says startViewTransition doesn't throw under
97
- // normal conditions, but Chromium has had edge cases (detached
98
- // document, extension interference). Clean up and unblock router.
99
- resolveAndClear();
100
- resolveLeave();
101
- }
102
- });
103
- });
104
-
105
- const offSuccess = router.subscribe(() => {
106
- const resolver = closeVT;
107
-
108
- successFired = true;
109
- closeVT = null;
110
-
111
- if (resolver === null) {
112
- currentVT = null;
113
- } else {
114
- // CRITICAL: CANNOT use requestAnimationFrame here. When the router
115
- // takes the async path (leave returned a Promise), subscribe fires
116
- // AFTER the browser has already transitioned VT into the
117
- // "update-callback-called" phase. In that phase Chromium sets
118
- // rendering suppression to true, which ALSO blocks rAF callbacks.
119
- // rAF would never fire → deferred never resolves → browser aborts
120
- // vt.ready with TimeoutError after 4s (observed in Chromium).
121
- //
122
- // setTimeout runs on the task queue independent of the rendering
123
- // pipeline, so it fires regardless of suppression. React's scheduler
124
- // uses MessageChannel tasks, which are queued before our setTimeout,
125
- // so the new DOM is committed by the time our callback runs.
126
- setTimeout(() => {
127
- resolver();
128
- currentVT = null;
129
- }, 0);
130
- }
131
- });
132
-
133
- return {
134
- destroy: () => {
135
- offLeave();
136
- offSuccess();
137
- currentVT?.skipTransition?.();
138
- currentVT = null;
139
- resolveAndClear();
140
- },
141
- };
142
- }
@@ -1,29 +0,0 @@
1
- export { injectRouter } from "./injectRouter";
2
-
3
- export { injectNavigator } from "./injectNavigator";
4
-
5
- export { injectRoute } from "./injectRoute";
6
-
7
- export { injectRouteNode } from "./injectRouteNode";
8
-
9
- export { injectRouteUtils } from "./injectRouteUtils";
10
-
11
- export { injectRouterTransition } from "./injectRouterTransition";
12
-
13
- export { injectIsActiveRoute } from "./injectIsActiveRoute";
14
-
15
- export { injectRouteExit } from "./injectRouteExit";
16
-
17
- export { injectRouteEnter } from "./injectRouteEnter";
18
-
19
- export type {
20
- RouteExitContext,
21
- RouteExitHandler,
22
- UseRouteExitOptions,
23
- } from "./injectRouteExit";
24
-
25
- export type {
26
- RouteEnterContext,
27
- RouteEnterHandler,
28
- UseRouteEnterOptions,
29
- } from "./injectRouteEnter";
@@ -1,31 +0,0 @@
1
- import { assertInInjectionContext } from "@angular/core";
2
- import { createActiveRouteSource } from "@real-router/sources";
3
-
4
- import { buildActiveRouteOptions } from "../internal/buildActiveRouteOptions";
5
- import { sourceToSignal } from "../sourceToSignal";
6
- import { injectRouter } from "./injectRouter";
7
-
8
- import type { Signal } from "@angular/core";
9
- import type { Params } from "@real-router/core";
10
-
11
- export function injectIsActiveRoute(
12
- routeName: string,
13
- params?: Params,
14
- options?: { strict?: boolean; ignoreQueryParams?: boolean; hash?: string },
15
- ): Signal<boolean> {
16
- assertInInjectionContext(injectIsActiveRoute);
17
-
18
- const router = injectRouter();
19
- const source = createActiveRouteSource(
20
- router,
21
- routeName,
22
- params,
23
- buildActiveRouteOptions(
24
- options?.strict ?? false,
25
- options?.ignoreQueryParams ?? true,
26
- options?.hash,
27
- ),
28
- );
29
-
30
- return sourceToSignal(source);
31
- }
@@ -1,12 +0,0 @@
1
- import { assertInInjectionContext } from "@angular/core";
2
-
3
- import { injectOrThrow } from "./injectOrThrow";
4
- import { NAVIGATOR } from "../providers";
5
-
6
- import type { Navigator } from "@real-router/core";
7
-
8
- export function injectNavigator(): Navigator {
9
- assertInInjectionContext(injectNavigator);
10
-
11
- return injectOrThrow(NAVIGATOR, "injectNavigator");
12
- }
@@ -1,19 +0,0 @@
1
- import { inject } from "@angular/core";
2
-
3
- import type { InjectionToken } from "@angular/core";
4
-
5
- export function injectOrThrow<T>(token: InjectionToken<T>, fnName: string): T {
6
- const value = inject(token, { optional: true });
7
-
8
- // Explicit null / undefined check — falsy guard would misfire on
9
- // legitimately falsy values (`0`, `""`, `false`) if the token were ever
10
- // typed for primitives. Today all our tokens hold object instances, but
11
- // pinning the check keeps the function safe for future typing changes.
12
- if (value === null || value === undefined) {
13
- throw new Error(
14
- `${fnName} must be used within a provideRealRouter context`,
15
- );
16
- }
17
-
18
- return value;
19
- }
@@ -1,39 +0,0 @@
1
- import { assertInInjectionContext } from "@angular/core";
2
-
3
- import { injectOrThrow } from "./injectOrThrow";
4
- import { ROUTE } from "../providers";
5
-
6
- import type { RouteSignals } from "../types";
7
- import type { Signal } from "@angular/core";
8
- import type { Params, State } from "@real-router/core";
9
- import type { RouteSnapshot } from "@real-router/sources";
10
-
11
- type NonNullRouteSignals<P extends Params> = Omit<
12
- RouteSignals<P>,
13
- "routeState"
14
- > & {
15
- readonly routeState: Signal<
16
- Omit<RouteSnapshot<P>, "route"> & { route: State<P> }
17
- >;
18
- };
19
-
20
- export function injectRoute<
21
- P extends Params = Params,
22
- >(): NonNullRouteSignals<P> {
23
- assertInInjectionContext(injectRoute);
24
-
25
- const signals = injectOrThrow(ROUTE, "injectRoute") as RouteSignals<P>;
26
-
27
- // Read the snapshot once: the signal is reactive, but the throw-guard
28
- // and any future use of the snapshot within this call should observe the
29
- // SAME value to avoid races.
30
- const snapshot = signals.routeState();
31
-
32
- if (!snapshot.route) {
33
- throw new Error(
34
- "injectRoute called with no active route. Did you forget to await router.start() before rendering, or is the router stopped/disposed?",
35
- );
36
- }
37
-
38
- return signals as NonNullRouteSignals<P>;
39
- }
@@ -1,117 +0,0 @@
1
- import { assertInInjectionContext, effect } from "@angular/core";
2
-
3
- import { injectRoute } from "./injectRoute";
4
-
5
- import type { State } from "@real-router/core";
6
-
7
- export interface RouteEnterContext {
8
- /** The route that was just activated. */
9
- route: State;
10
- /** The route that was active immediately before this navigation. */
11
- previousRoute: State;
12
- }
13
-
14
- export type RouteEnterHandler = (context: RouteEnterContext) => void;
15
-
16
- export interface UseRouteEnterOptions {
17
- /**
18
- * Skip the handler when `route.name === previousRoute.name`
19
- * (sort/filter/query-only navigations on the same route). Default:
20
- * `true`. Symmetric with `injectRouteExit`'s same-name option.
21
- */
22
- skipSameRoute?: boolean;
23
- }
24
-
25
- /**
26
- * Fire `handler` once when the component is created as a result of a
27
- * navigation. Mirror of `injectRouteExit` for the entry side.
28
- *
29
- * What this function covers that an ad-hoc `effect()` + `injectRoute()`
30
- * doesn't:
31
- *
32
- * - **Skip-initial**: handler is skipped when there is no
33
- * `route.transition.from` (i.e. first-load mount). Most consumers
34
- * want to fire side effects only on real navigations, not on
35
- * hydration.
36
- * - **Same-route skip** (default): handler is skipped when
37
- * `route.transition.from === route.name`. Sort/filter/query-only
38
- * navigations re-run the effect (because the `route` reference
39
- * changes), but they are not "entries" in the animation / analytics
40
- * sense. Opt out with `skipSameRoute: false`.
41
- * - **Mount-time `route` / `previousRoute` snapshot**: handler receives
42
- * the values that were live at the moment of effect activation.
43
- *
44
- * Effect cleanup is wired through the injection context's `DestroyRef`
45
- * (Angular's `effect()` ties into the active context automatically).
46
- * Must be called within an injection context (constructor, field
47
- * initializer, or `runInInjectionContext`).
48
- *
49
- * **Handler reactivity (Angular):** `inject*` functions run **once**
50
- * during component construction; `handler` is captured in closure at the
51
- * call site. The common Angular pattern is to pass a class method —
52
- * its identity is stable across change detection. To vary behavior
53
- * over time, read signals **inside** the handler body.
54
- *
55
- * @example Direction-aware entry animation
56
- * ```ts
57
- * \@Component({ ... })
58
- * class PageComponent {
59
- * private el = inject(ElementRef<HTMLElement>);
60
- *
61
- * constructor() {
62
- * injectRouteEnter(({ route }) => {
63
- * const direction = route.context.browser?.direction;
64
- * this.el.nativeElement.classList.add(
65
- * direction === "back" ? "slide-from-left" : "slide-from-right",
66
- * );
67
- * });
68
- * }
69
- * }
70
- * ```
71
- *
72
- * @example Analytics page-enter event (skip-initial built-in)
73
- * ```ts
74
- * injectRouteEnter(({ route, previousRoute }) => {
75
- * analytics.track("page_enter", {
76
- * route: route.name,
77
- * from: previousRoute.name,
78
- * });
79
- * });
80
- * ```
81
- */
82
- export function injectRouteEnter(
83
- handler: RouteEnterHandler,
84
- options?: UseRouteEnterOptions,
85
- ): void {
86
- assertInInjectionContext(injectRouteEnter);
87
-
88
- const { routeState } = injectRoute();
89
- const skipSameRoute = options?.skipSameRoute ?? true;
90
-
91
- effect(() => {
92
- const { route, previousRoute } = routeState();
93
-
94
- // Early-exit guards, top-down:
95
- //
96
- // - **Skip-initial**: `state.transition.from` is undefined only
97
- // for the very first state committed by `router.start()`.
98
- // - **Skip-same-route**: query-only navigations have
99
- // `transition.from === route.name`. Opt-out via
100
- // `skipSameRoute: false`.
101
- if (!route.transition.from) {
102
- return;
103
- }
104
- if (skipSameRoute && route.transition.from === route.name) {
105
- return;
106
- }
107
- // `previousRoute` is guaranteed populated whenever `route.transition.from`
108
- // is set — core writes them together. The dead-code throw-guard that used
109
- // to live here (review §8a LOW) is removed; the narrowing below is the
110
- // type-safe equivalent and avoids the no-non-null-assertion lint.
111
- if (!previousRoute) {
112
- return;
113
- }
114
-
115
- handler({ route, previousRoute });
116
- });
117
- }
@@ -1,118 +0,0 @@
1
- import { DestroyRef, assertInInjectionContext, inject } from "@angular/core";
2
-
3
- import { injectRouter } from "./injectRouter";
4
-
5
- import type { State } from "@real-router/core";
6
-
7
- export interface RouteExitContext {
8
- /** The route being left. */
9
- route: State;
10
- /** The route being navigated to. */
11
- nextRoute: State;
12
- /**
13
- * AbortSignal that fires when this navigation is superseded by a later
14
- * one (rapid clicks). Already filtered: when the handler runs,
15
- * `signal.aborted` is guaranteed to be `false`. Use
16
- * `signal.addEventListener("abort", cleanup, { once: true })` for
17
- * cleanup that must run on cancellation.
18
- */
19
- signal: AbortSignal;
20
- }
21
-
22
- export interface UseRouteExitOptions {
23
- /**
24
- * Skip the handler when `route.name === nextRoute.name`
25
- * (sort/filter/query-only navigations on the same route). Default:
26
- * `true`.
27
- */
28
- skipSameRoute?: boolean;
29
- }
30
-
31
- export type RouteExitHandler = (
32
- context: RouteExitContext,
33
- ) => void | Promise<void>;
34
-
35
- /**
36
- * Subscribe to the router's leave-window with the universal guards baked
37
- * in. Wraps `router.subscribeLeave` so consumers don't repeat the same
38
- * boilerplate every time:
39
- *
40
- * - **Reentrant abort pre-check**: if `signal.aborted` is already `true`
41
- * when the handler would run (rapid navigation superseded a slower
42
- * one), the handler is skipped entirely.
43
- * - **Same-route skip**: by default, `route.name === nextRoute.name`
44
- * short-circuits the handler — query-only navigations skip the work.
45
- * Opt out with `skipSameRoute: false`.
46
- *
47
- * Cleanup is bound to the injection context's `DestroyRef`. Must be
48
- * called within an injection context (constructor, field initializer,
49
- * or `runInInjectionContext`).
50
- *
51
- * If the handler returns a Promise, the router blocks on it. If the
52
- * Promise resolves, navigation proceeds. If it rejects, the router emits
53
- * `TRANSITION_CANCELLED`.
54
- *
55
- * **Handler reactivity (Angular):** `inject*` functions run **once**
56
- * during component construction; `handler` is captured in closure at the
57
- * call site. The common Angular pattern is to pass a class method
58
- * (`this.onExit.bind(this)` or an arrow-property) — its identity is
59
- * stable across change detection. To vary behavior over time, read
60
- * signals **inside** the handler body — do not rely on swapping the
61
- * handler reference.
62
- *
63
- * @example Animation
64
- * ```ts
65
- * \@Component({ ... })
66
- * class FadeOutComponent {
67
- * private el = inject(ElementRef<HTMLElement>);
68
- *
69
- * constructor() {
70
- * injectRouteExit(async ({ signal }) => {
71
- * const el = this.el.nativeElement;
72
- * el.classList.add("fade-out");
73
- * const cleanup = () => el.classList.remove("fade-out");
74
- * signal.addEventListener("abort", cleanup, { once: true });
75
- * try {
76
- * el.getBoundingClientRect();
77
- * await Promise.allSettled(el.getAnimations().map((a) => a.finished));
78
- * } finally {
79
- * cleanup();
80
- * }
81
- * });
82
- * }
83
- * }
84
- * ```
85
- *
86
- * @example Auto-save form draft
87
- * ```ts
88
- * injectRouteExit(async ({ signal }) => {
89
- * if (this.formState.dirty) {
90
- * await this.api.saveDraft(this.formState, { signal });
91
- * }
92
- * });
93
- * ```
94
- */
95
- export function injectRouteExit(
96
- handler: RouteExitHandler,
97
- options?: UseRouteExitOptions,
98
- ): void {
99
- assertInInjectionContext(injectRouteExit);
100
-
101
- const router = injectRouter();
102
- const destroyRef = inject(DestroyRef);
103
- const skipSameRoute = options?.skipSameRoute ?? true;
104
-
105
- const off = router.subscribeLeave(({ route, nextRoute, signal }) => {
106
- if (skipSameRoute && route.name === nextRoute.name) {
107
- return;
108
- }
109
-
110
- if (signal.aborted) {
111
- return;
112
- }
113
-
114
- return handler({ route, nextRoute, signal });
115
- });
116
-
117
- destroyRef.onDestroy(off);
118
- }
@@ -1,19 +0,0 @@
1
- import { assertInInjectionContext } from "@angular/core";
2
- import { getNavigator } from "@real-router/core";
3
- import { createRouteNodeSource } from "@real-router/sources";
4
-
5
- import { sourceToSignal } from "../sourceToSignal";
6
- import { injectRouter } from "./injectRouter";
7
-
8
- import type { RouteSignals } from "../types";
9
-
10
- export function injectRouteNode(nodeName: string): RouteSignals {
11
- assertInInjectionContext(injectRouteNode);
12
-
13
- const router = injectRouter();
14
- const navigator = getNavigator(router);
15
- const source = createRouteNodeSource(router, nodeName);
16
- const routeState = sourceToSignal(source);
17
-
18
- return { routeState, navigator };
19
- }
@@ -1,15 +0,0 @@
1
- import { assertInInjectionContext } from "@angular/core";
2
- import { getPluginApi } from "@real-router/core/api";
3
- import { getRouteUtils } from "@real-router/route-utils";
4
-
5
- import { injectRouter } from "./injectRouter";
6
-
7
- import type { RouteUtils } from "@real-router/route-utils";
8
-
9
- export function injectRouteUtils(): RouteUtils {
10
- assertInInjectionContext(injectRouteUtils);
11
-
12
- const router = injectRouter();
13
-
14
- return getRouteUtils(getPluginApi(router).getTree());
15
- }
@@ -1,12 +0,0 @@
1
- import { assertInInjectionContext } from "@angular/core";
2
-
3
- import { injectOrThrow } from "./injectOrThrow";
4
- import { ROUTER } from "../providers";
5
-
6
- import type { Router } from "@real-router/core";
7
-
8
- export function injectRouter(): Router {
9
- assertInInjectionContext(injectRouter);
10
-
11
- return injectOrThrow(ROUTER, "injectRouter");
12
- }
@@ -1,17 +0,0 @@
1
- import { assertInInjectionContext } from "@angular/core";
2
- import { getTransitionSource } from "@real-router/sources";
3
-
4
- import { sourceToSignal } from "../sourceToSignal";
5
- import { injectRouter } from "./injectRouter";
6
-
7
- import type { Signal } from "@angular/core";
8
- import type { RouterTransitionSnapshot } from "@real-router/sources";
9
-
10
- export function injectRouterTransition(): Signal<RouterTransitionSnapshot> {
11
- assertInInjectionContext(injectRouterTransition);
12
-
13
- const router = injectRouter();
14
- const source = getTransitionSource(router);
15
-
16
- return sourceToSignal(source);
17
- }
package/src/index.ts DELETED
@@ -1,63 +0,0 @@
1
- export { provideRealRouter, ROUTER, NAVIGATOR, ROUTE } from "./providers";
2
-
3
- export type { RealRouterOptions } from "./providers";
4
-
5
- export { provideRealRouterFactory } from "./providersFactory";
6
-
7
- export type {
8
- RealRouterFactoryOptions,
9
- RequestDepsFactory,
10
- RequestPluginsFactory,
11
- } from "./providersFactory";
12
-
13
- export { sourceToSignal } from "./sourceToSignal";
14
-
15
- // Note: SSR-feature exports (`ClientOnly`, `ServerOnly`, `injectDeferred`)
16
- // have moved to the `/ssr` subpath — import them from
17
- // `@real-router/angular/ssr` to opt into the SSR-feature surface.
18
- export {
19
- injectRouter,
20
- injectNavigator,
21
- injectRoute,
22
- injectRouteNode,
23
- injectRouteUtils,
24
- injectRouterTransition,
25
- injectIsActiveRoute,
26
- injectRouteExit,
27
- injectRouteEnter,
28
- } from "./functions";
29
-
30
- export type {
31
- RouteExitContext,
32
- RouteExitHandler,
33
- UseRouteExitOptions,
34
- RouteEnterContext,
35
- RouteEnterHandler,
36
- UseRouteEnterOptions,
37
- } from "./functions";
38
-
39
- export { RouteView } from "./components/RouteView";
40
-
41
- export { RouterErrorBoundary } from "./components/RouterErrorBoundary";
42
-
43
- export { NavigationAnnouncer } from "./components/NavigationAnnouncer";
44
-
45
- export { RouteMatch } from "./directives/RouteMatch";
46
-
47
- export { RouteSelf } from "./directives/RouteSelf";
48
-
49
- export { RouteNotFound } from "./directives/RouteNotFound";
50
-
51
- export { RealLink } from "./directives/RealLink";
52
-
53
- export { RealLinkActive } from "./directives/RealLinkActive";
54
-
55
- export type { RouteSignals, ErrorContext } from "./types";
56
-
57
- export type {
58
- RouteSnapshot,
59
- RouterTransitionSnapshot,
60
- RouterErrorSnapshot,
61
- } from "@real-router/sources";
62
-
63
- export type { Navigator } from "@real-router/core";
@@ -1,20 +0,0 @@
1
- import type { ActiveRouteSourceOptions } from "@real-router/sources";
2
-
3
- /**
4
- * Build the `options` literal for `createActiveRouteSource` while honoring
5
- * `exactOptionalPropertyTypes` — the type forbids passing `{ hash: undefined }`
6
- * literally (#532), so callers must conditionally include the `hash` key only
7
- * when a value was provided.
8
- *
9
- * Used by `RealLink`, `RealLinkActive`, and `injectIsActiveRoute` — extracted
10
- * from three identical ternaries (review-2026-05-16 §8a LOW).
11
- */
12
- export function buildActiveRouteOptions(
13
- strict: boolean,
14
- ignoreQueryParams: boolean,
15
- hash: string | undefined,
16
- ): ActiveRouteSourceOptions {
17
- return hash === undefined
18
- ? { strict, ignoreQueryParams }
19
- : { strict, ignoreQueryParams, hash };
20
- }