@real-router/solid 0.5.2 → 0.7.0

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 (34) hide show
  1. package/README.md +15 -3
  2. package/dist/cjs/index.d.ts +20 -1
  3. package/dist/cjs/index.js +236 -18
  4. package/dist/esm/index.d.mts +20 -1
  5. package/dist/esm/index.mjs +236 -18
  6. package/dist/types/RouterProvider.d.ts +2 -0
  7. package/dist/types/RouterProvider.d.ts.map +1 -1
  8. package/dist/types/components/Link.d.ts.map +1 -1
  9. package/dist/types/components/RouteView/RouteView.d.ts +3 -2
  10. package/dist/types/components/RouteView/RouteView.d.ts.map +1 -1
  11. package/dist/types/components/RouteView/components.d.ts +12 -2
  12. package/dist/types/components/RouteView/components.d.ts.map +1 -1
  13. package/dist/types/components/RouteView/helpers.d.ts.map +1 -1
  14. package/dist/types/components/RouteView/index.d.ts +1 -1
  15. package/dist/types/components/RouteView/index.d.ts.map +1 -1
  16. package/dist/types/components/RouteView/types.d.ts +6 -0
  17. package/dist/types/components/RouteView/types.d.ts.map +1 -1
  18. package/dist/types/directives/link.d.ts.map +1 -1
  19. package/dist/types/dom-utils/index.d.ts +2 -0
  20. package/dist/types/dom-utils/index.d.ts.map +1 -1
  21. package/dist/types/dom-utils/scroll-restore.d.ts +11 -0
  22. package/dist/types/dom-utils/scroll-restore.d.ts.map +1 -0
  23. package/dist/types/index.d.ts +1 -1
  24. package/dist/types/index.d.ts.map +1 -1
  25. package/package.json +3 -3
  26. package/src/RouterProvider.tsx +15 -1
  27. package/src/components/Link.tsx +1 -5
  28. package/src/components/RouteView/RouteView.tsx +7 -2
  29. package/src/components/RouteView/components.tsx +25 -2
  30. package/src/components/RouteView/helpers.tsx +67 -21
  31. package/src/components/RouteView/index.ts +1 -0
  32. package/src/components/RouteView/types.ts +7 -0
  33. package/src/directives/link.tsx +1 -5
  34. package/src/index.tsx +1 -0
package/README.md CHANGED
@@ -320,18 +320,30 @@ Enable screen reader announcements for route changes:
320
320
 
321
321
  When enabled, a visually hidden `aria-live` region announces each navigation. Focus moves to the first `<h1>` on the new page. See [Accessibility guide](https://github.com/greydragon888/real-router/wiki/Accessibility) for details.
322
322
 
323
+ ## Scroll Restoration
324
+
325
+ Opt-in preservation of scroll position across navigations:
326
+
327
+ ```tsx
328
+ <RouterProvider router={router} scrollRestoration={{ mode: "restore" }}>
329
+ {/* Your app */}
330
+ </RouterProvider>
331
+ ```
332
+
333
+ Restores scroll on back/forward, scrolls to top (or `#hash`) on push. Three modes: `"restore"` (default), `"top"`, `"manual"`. Custom containers via `scrollContainer: () => HTMLElement | null`. Options are read once on mount — changing the prop at runtime does not reconfigure the utility (Solid `onMount` is non-reactive). See [Scroll Restoration guide](https://github.com/greydragon888/real-router/wiki/Scroll-Restoration) for details.
334
+
323
335
  ## Documentation
324
336
 
325
337
  Full documentation: [Wiki](https://github.com/greydragon888/real-router/wiki)
326
338
 
327
- - [RouterProvider](https://github.com/greydragon888/real-router/wiki/RouterProvider) · [RouteView](https://github.com/greydragon888/real-router/wiki/RouteView) · [RouterErrorBoundary](https://github.com/greydragon888/real-router/wiki/RouterErrorBoundary) · [Link](https://github.com/greydragon888/real-router/wiki/Link)
339
+ - [RouterProvider](https://github.com/greydragon888/real-router/wiki/RouterProvider) · [RouteView](https://github.com/greydragon888/real-router/wiki/RouteView) · [RouterErrorBoundary](https://github.com/greydragon888/real-router/wiki/RouterErrorBoundary) · [Link](https://github.com/greydragon888/real-router/wiki/Link) · [Scroll Restoration](https://github.com/greydragon888/real-router/wiki/Scroll-Restoration)
328
340
  - [useRouter](https://github.com/greydragon888/real-router/wiki/useRouter) · [useRoute](https://github.com/greydragon888/real-router/wiki/useRoute) · [useRouteNode](https://github.com/greydragon888/real-router/wiki/useRouteNode) · [useNavigator](https://github.com/greydragon888/real-router/wiki/useNavigator) · [useRouteUtils](https://github.com/greydragon888/real-router/wiki/useRouteUtils) · [useRouterTransition](https://github.com/greydragon888/real-router/wiki/useRouterTransition)
329
341
 
330
342
  ## Examples
331
343
 
332
- 14 runnable examples — each is a standalone Vite app. Run: `cd examples/solid/basic && pnpm dev`
344
+ 14 runnable examples — each is a standalone Vite app. Run: `cd examples/web/solid/basic && pnpm dev`
333
345
 
334
- [basic](../../examples/solid/basic) · [nested-routes](../../examples/solid/nested-routes) · [auth-guards](../../examples/solid/auth-guards) · [data-loading](../../examples/solid/data-loading) · [lazy-loading](../../examples/solid/lazy-loading) · [async-guards](../../examples/solid/async-guards) · [hash-routing](../../examples/solid/hash-routing) · [persistent-params](../../examples/solid/persistent-params) · [error-handling](../../examples/solid/error-handling) · [dynamic-routes](../../examples/solid/dynamic-routes) · [store-based-state](../../examples/solid/store-based-state) · [use-link-directive](../../examples/solid/use-link-directive) · [signal-primitives](../../examples/solid/signal-primitives) · [combined](../../examples/solid/combined)
346
+ [basic](../../examples/web/solid/basic) · [nested-routes](../../examples/web/solid/nested-routes) · [auth-guards](../../examples/web/solid/auth-guards) · [data-loading](../../examples/web/solid/data-loading) · [lazy-loading](../../examples/web/solid/lazy-loading) · [async-guards](../../examples/web/solid/async-guards) · [hash-routing](../../examples/web/solid/hash-routing) · [persistent-params](../../examples/web/solid/persistent-params) · [error-handling](../../examples/web/solid/error-handling) · [dynamic-routes](../../examples/web/solid/dynamic-routes) · [store-based-state](../../examples/web/solid/store-based-state) · [use-link-directive](../../examples/web/solid/use-link-directive) · [signal-primitives](../../examples/web/solid/signal-primitives) · [combined](../../examples/web/solid/combined)
335
347
 
336
348
  ## Related Packages
337
349
 
@@ -17,6 +17,12 @@ interface MatchProps {
17
17
  readonly fallback?: JSX.Element;
18
18
  readonly children: JSX.Element;
19
19
  }
20
+ interface SelfProps {
21
+ /** Fallback content while children are suspended. */
22
+ readonly fallback?: JSX.Element;
23
+ /** Content to render when the active route name equals the parent RouteView's nodeName. */
24
+ readonly children: JSX.Element;
25
+ }
20
26
  interface NotFoundProps {
21
27
  readonly children: JSX.Element;
22
28
  }
@@ -25,6 +31,10 @@ declare function Match(props: MatchProps): JSX.Element;
25
31
  declare namespace Match {
26
32
  var displayName: string;
27
33
  }
34
+ declare function Self(props: SelfProps): JSX.Element;
35
+ declare namespace Self {
36
+ var displayName: string;
37
+ }
28
38
  declare function NotFound(props: NotFoundProps): JSX.Element;
29
39
  declare namespace NotFound {
30
40
  var displayName: string;
@@ -36,6 +46,7 @@ declare namespace RouteViewRoot {
36
46
  }
37
47
  declare const RouteView: typeof RouteViewRoot & {
38
48
  Match: typeof Match;
49
+ Self: typeof Self;
39
50
  NotFound: typeof NotFound;
40
51
  };
41
52
 
@@ -89,9 +100,17 @@ declare function useRouteNodeStore(nodeName: string): RouteState;
89
100
 
90
101
  declare function useRouterTransition(): Accessor<RouterTransitionSnapshot>;
91
102
 
103
+ type ScrollRestorationMode = "restore" | "top" | "manual";
104
+ interface ScrollRestorationOptions {
105
+ mode?: ScrollRestorationMode | undefined;
106
+ anchorScrolling?: boolean | undefined;
107
+ scrollContainer?: (() => HTMLElement | null) | undefined;
108
+ }
109
+
92
110
  interface RouteProviderProps {
93
111
  router: Router;
94
112
  announceNavigation?: boolean;
113
+ scrollRestoration?: ScrollRestorationOptions;
95
114
  }
96
115
  declare function RouterProvider(props: ParentProps<RouteProviderProps>): JSX.Element;
97
116
 
@@ -108,4 +127,4 @@ declare function createSignalFromSource<T>(source: RouterSource<T>): Accessor<T>
108
127
  declare function createStoreFromSource<T extends object>(source: RouterSource<T>): T;
109
128
 
110
129
  export { Link, RouteContext, RouteView, RouterContext, RouterErrorBoundary, RouterProvider, createSignalFromSource, createStoreFromSource, link, useNavigator, useRoute, useRouteNode, useRouteNodeStore, useRouteStore, useRouteUtils, useRouter, useRouterTransition };
111
- export type { LinkDirectiveOptions, LinkProps, RouteState, MatchProps as RouteViewMatchProps, NotFoundProps as RouteViewNotFoundProps, RouteViewProps, RouterErrorBoundaryProps };
130
+ export type { LinkDirectiveOptions, LinkProps, RouteState, MatchProps as RouteViewMatchProps, NotFoundProps as RouteViewNotFoundProps, RouteViewProps, SelfProps as RouteViewSelfProps, RouterErrorBoundaryProps };
package/dist/cjs/index.js CHANGED
@@ -11,6 +11,7 @@ var core = require('@real-router/core');
11
11
  // Local (non-global) Symbols — Symbol.for() would expose markers to spoofing
12
12
  // via the global Symbol registry. See Gotchas section "RouteView Marker Objects".
13
13
  const MATCH_MARKER = Symbol("RouteView.Match");
14
+ const SELF_MARKER = Symbol("RouteView.Self");
14
15
  const NOT_FOUND_MARKER = Symbol("RouteView.NotFound");
15
16
  function Match(props) {
16
17
  const result = {
@@ -29,6 +30,19 @@ function Match(props) {
29
30
  return result;
30
31
  }
31
32
  Match.displayName = "RouteView.Match";
33
+ function Self(props) {
34
+ const result = {
35
+ $$type: SELF_MARKER,
36
+ fallback: props.fallback,
37
+ get children() {
38
+ return props.children;
39
+ }
40
+ };
41
+
42
+ // See Match for the marker-pattern rationale.
43
+ return result;
44
+ }
45
+ Self.displayName = "RouteView.Self";
32
46
  function NotFound(props) {
33
47
  const result = {
34
48
  $$type: NOT_FOUND_MARKER,
@@ -51,6 +65,9 @@ function isSegmentMatch(routeName, fullSegmentName, exact) {
51
65
  function isMatchMarker(value) {
52
66
  return value != null && typeof value === "object" && "$$type" in value && value.$$type === MATCH_MARKER;
53
67
  }
68
+ function isSelfMarker(value) {
69
+ return value != null && typeof value === "object" && "$$type" in value && value.$$type === SELF_MARKER;
70
+ }
54
71
  function isNotFoundMarker(value) {
55
72
  return value != null && typeof value === "object" && "$$type" in value && value.$$type === NOT_FOUND_MARKER;
56
73
  }
@@ -64,11 +81,48 @@ function collectElements(children, result) {
64
81
  }
65
82
  return;
66
83
  }
67
- if (isMatchMarker(children) || isNotFoundMarker(children)) {
84
+ if (isMatchMarker(children) || isSelfMarker(children) || isNotFoundMarker(children)) {
68
85
  result.push(children);
69
86
  }
70
87
  }
88
+
89
+ // child.children is a getter — read it INSIDE the JSX expression so Solid
90
+ // creates a reactive dependency. Pulling it into a variable freezes the
91
+ // value at template-build time and breaks Suspense fallback transitions
92
+ // (lazy() resolution).
93
+ function renderMatch(child) {
94
+ return child.fallback === undefined ? child.children : web.createComponent(solidJs.Suspense, {
95
+ get fallback() {
96
+ return child.fallback;
97
+ },
98
+ get children() {
99
+ return child.children;
100
+ }
101
+ });
102
+ }
103
+ function renderSelf(self) {
104
+ return self.fallback === undefined ? self.children : web.createComponent(solidJs.Suspense, {
105
+ get fallback() {
106
+ return self.fallback;
107
+ },
108
+ get children() {
109
+ return self.children;
110
+ }
111
+ });
112
+ }
113
+ function processMatchChild(child, routeName, nodeName) {
114
+ const {
115
+ segment,
116
+ exact
117
+ } = child;
118
+ const fullSegmentName = nodeName ? `${nodeName}.${segment}` : segment;
119
+ if (!isSegmentMatch(routeName, fullSegmentName, exact)) {
120
+ return null;
121
+ }
122
+ return renderMatch(child);
123
+ }
71
124
  function buildRenderList(elements, routeName, nodeName) {
125
+ let selfMarker = null;
72
126
  let notFoundChildren = null;
73
127
  let activeMatchFound = false;
74
128
  const rendered = [];
@@ -77,28 +131,25 @@ function buildRenderList(elements, routeName, nodeName) {
77
131
  notFoundChildren = child.children;
78
132
  continue;
79
133
  }
80
- if (activeMatchFound) {
134
+ if (isSelfMarker(child)) {
135
+ selfMarker ??= child;
81
136
  continue;
82
137
  }
83
- const {
84
- segment,
85
- exact,
86
- fallback
87
- } = child;
88
- const fullSegmentName = nodeName ? `${nodeName}.${segment}` : segment;
89
- if (!isSegmentMatch(routeName, fullSegmentName, exact)) {
138
+ if (activeMatchFound) {
90
139
  continue;
91
140
  }
92
- activeMatchFound = true;
93
- rendered.push(fallback === undefined ? child.children : web.createComponent(solidJs.Suspense, {
94
- fallback: fallback,
95
- get children() {
96
- return child.children;
97
- }
98
- }));
141
+ const matchRendered = processMatchChild(child, routeName, nodeName);
142
+ if (matchRendered !== null) {
143
+ activeMatchFound = true;
144
+ rendered.push(matchRendered);
145
+ }
99
146
  }
100
- if (!activeMatchFound && routeName === core.UNKNOWN_ROUTE && notFoundChildren !== null) {
101
- rendered.push(notFoundChildren);
147
+ if (!activeMatchFound) {
148
+ if (selfMarker !== null && routeName === nodeName) {
149
+ rendered.push(renderSelf(selfMarker));
150
+ } else if (routeName === core.UNKNOWN_ROUTE && notFoundChildren !== null) {
151
+ rendered.push(notFoundChildren);
152
+ }
102
153
  }
103
154
  return rendered;
104
155
  }
@@ -157,6 +208,7 @@ function RouteViewRoot(props) {
157
208
  RouteViewRoot.displayName = "RouteView";
158
209
  const RouteView = Object.assign(RouteViewRoot, {
159
210
  Match,
211
+ Self,
160
212
  NotFound
161
213
  });
162
214
 
@@ -284,6 +336,163 @@ function manageFocus(h1) {
284
336
  });
285
337
  }
286
338
 
339
+ const STORAGE_KEY = "real-router:scroll";
340
+ const NOOP_INSTANCE = Object.freeze({
341
+ destroy: () => {
342
+ /* no-op */
343
+ }
344
+ });
345
+ function createScrollRestoration(router, options) {
346
+ if (typeof globalThis.window === "undefined") {
347
+ return NOOP_INSTANCE;
348
+ }
349
+ const mode = options?.mode ?? "restore";
350
+
351
+ // mode "manual" = utility does nothing. Don't flip history.scrollRestoration,
352
+ // don't subscribe, don't register pagehide — leave the browser's native
353
+ // auto-restore intact for the app to override if it wants to.
354
+ if (mode === "manual") {
355
+ return NOOP_INSTANCE;
356
+ }
357
+ const anchorEnabled = options?.anchorScrolling ?? true;
358
+ const getContainer = options?.scrollContainer;
359
+ const prevScrollRestoration = history.scrollRestoration;
360
+ try {
361
+ history.scrollRestoration = "manual";
362
+ } catch {
363
+ // Ignore — some embedded contexts may reject the assignment.
364
+ }
365
+
366
+ // Resolve the container lazily on every event so containers mounted AFTER
367
+ // the provider still get correct scroll handling. Falls back to window when
368
+ // the getter is absent or returns null (pre-mount).
369
+ const readPos = () => {
370
+ const element = getContainer?.();
371
+ return element ? element.scrollTop : globalThis.scrollY;
372
+ };
373
+ const writePos = top => {
374
+ const element = getContainer?.();
375
+ if (element) {
376
+ element.scrollTop = top;
377
+ } else {
378
+ globalThis.scrollTo(0, top);
379
+ }
380
+ };
381
+ const scrollToHashOrTop = () => {
382
+ const hash = globalThis.location.hash;
383
+ if (anchorEnabled && hash.length > 1) {
384
+ // location.hash is percent-encoded; ids in the DOM are the raw string.
385
+ // Decode for the match. Fall back to the raw slice if the hash contains
386
+ // a malformed escape sequence (decodeURIComponent throws on those).
387
+ let id;
388
+ try {
389
+ id = decodeURIComponent(hash.slice(1));
390
+ } catch {
391
+ id = hash.slice(1);
392
+ }
393
+
394
+ // eslint-disable-next-line unicorn/prefer-query-selector -- ids may contain CSS-unsafe chars
395
+ const element = document.getElementById(id);
396
+ if (element) {
397
+ element.scrollIntoView();
398
+ return;
399
+ }
400
+ }
401
+ writePos(0);
402
+ };
403
+ let destroyed = false;
404
+ const unsubscribe = router.subscribe(({
405
+ route,
406
+ previousRoute
407
+ }) => {
408
+ const nav = route.context.navigation;
409
+
410
+ // Browsers dispatch reload as the initial navigation after refresh, so
411
+ // previousRoute is undefined and capture is naturally skipped. The
412
+ // pre-refresh position was already persisted via pagehide.
413
+ if (previousRoute) {
414
+ putPos(keyOf(previousRoute), readPos());
415
+ }
416
+
417
+ // Single rAF so DOM is committed before we read anchors / write scroll.
418
+ // Guard against destroy() racing with the callback.
419
+ requestAnimationFrame(() => {
420
+ if (destroyed) {
421
+ return;
422
+ }
423
+ if (mode === "top" || !nav) {
424
+ scrollToHashOrTop();
425
+ return;
426
+ }
427
+ if (nav.navigationType === "replace") {
428
+ return;
429
+ }
430
+ if (nav.direction === "back" || nav.navigationType === "traverse" || nav.navigationType === "reload") {
431
+ writePos(loadStore()[keyOf(route)] ?? 0);
432
+ return;
433
+ }
434
+ scrollToHashOrTop();
435
+ });
436
+ });
437
+ const onPageHide = () => {
438
+ const current = router.getState();
439
+ if (current) {
440
+ putPos(keyOf(current), readPos());
441
+ }
442
+ };
443
+ globalThis.addEventListener("pagehide", onPageHide);
444
+ return {
445
+ destroy: () => {
446
+ if (destroyed) {
447
+ return;
448
+ }
449
+ destroyed = true;
450
+ unsubscribe();
451
+ globalThis.removeEventListener("pagehide", onPageHide);
452
+ try {
453
+ history.scrollRestoration = prevScrollRestoration;
454
+ } catch {
455
+ // Ignore.
456
+ }
457
+ }
458
+ };
459
+ }
460
+ function keyOf(state) {
461
+ return `${state.name}:${canonicalJson(state.params)}`;
462
+ }
463
+ function loadStore() {
464
+ try {
465
+ const raw = sessionStorage.getItem(STORAGE_KEY);
466
+ return raw ? JSON.parse(raw) : {};
467
+ } catch {
468
+ return {};
469
+ }
470
+ }
471
+ function putPos(key, pos) {
472
+ try {
473
+ const store = loadStore();
474
+ store[key] = pos;
475
+ sessionStorage.setItem(STORAGE_KEY, JSON.stringify(store));
476
+ } catch {
477
+ // Ignore quota / security errors.
478
+ }
479
+ }
480
+ function canonicalJson(value) {
481
+ return JSON.stringify(value, canonicalReplacer);
482
+ }
483
+ function canonicalReplacer(_key, val) {
484
+ if (val !== null && typeof val === "object" && !Array.isArray(val)) {
485
+ const sorted = {};
486
+ // eslint-disable-next-line unicorn/no-array-sort -- ng-packagr uses pre-ES2023 lib; toSorted unavailable
487
+ const keys = Object.keys(val).sort((left, right) => left.localeCompare(right));
488
+ for (const key of keys) {
489
+ sorted[key] = val[key];
490
+ }
491
+ return sorted;
492
+ }
493
+ return val;
494
+ }
495
+
287
496
  function shouldNavigate(evt) {
288
497
  return evt.button === 0 && !evt.metaKey && !evt.altKey && !evt.ctrlKey && !evt.shiftKey;
289
498
  }
@@ -514,6 +723,15 @@ function RouterProvider(props) {
514
723
  announcer.destroy();
515
724
  });
516
725
  });
726
+ solidJs.onMount(() => {
727
+ if (!props.scrollRestoration) {
728
+ return;
729
+ }
730
+ const sr = createScrollRestoration(props.router, props.scrollRestoration);
731
+ solidJs.onCleanup(() => {
732
+ sr.destroy();
733
+ });
734
+ });
517
735
  const navigator = core.getNavigator(props.router);
518
736
  const routeSource = sources.createRouteSource(props.router);
519
737
  const routeSignal = createSignalFromSource(routeSource);
@@ -17,6 +17,12 @@ interface MatchProps {
17
17
  readonly fallback?: JSX.Element;
18
18
  readonly children: JSX.Element;
19
19
  }
20
+ interface SelfProps {
21
+ /** Fallback content while children are suspended. */
22
+ readonly fallback?: JSX.Element;
23
+ /** Content to render when the active route name equals the parent RouteView's nodeName. */
24
+ readonly children: JSX.Element;
25
+ }
20
26
  interface NotFoundProps {
21
27
  readonly children: JSX.Element;
22
28
  }
@@ -25,6 +31,10 @@ declare function Match(props: MatchProps): JSX.Element;
25
31
  declare namespace Match {
26
32
  var displayName: string;
27
33
  }
34
+ declare function Self(props: SelfProps): JSX.Element;
35
+ declare namespace Self {
36
+ var displayName: string;
37
+ }
28
38
  declare function NotFound(props: NotFoundProps): JSX.Element;
29
39
  declare namespace NotFound {
30
40
  var displayName: string;
@@ -36,6 +46,7 @@ declare namespace RouteViewRoot {
36
46
  }
37
47
  declare const RouteView: typeof RouteViewRoot & {
38
48
  Match: typeof Match;
49
+ Self: typeof Self;
39
50
  NotFound: typeof NotFound;
40
51
  };
41
52
 
@@ -89,9 +100,17 @@ declare function useRouteNodeStore(nodeName: string): RouteState;
89
100
 
90
101
  declare function useRouterTransition(): Accessor<RouterTransitionSnapshot>;
91
102
 
103
+ type ScrollRestorationMode = "restore" | "top" | "manual";
104
+ interface ScrollRestorationOptions {
105
+ mode?: ScrollRestorationMode | undefined;
106
+ anchorScrolling?: boolean | undefined;
107
+ scrollContainer?: (() => HTMLElement | null) | undefined;
108
+ }
109
+
92
110
  interface RouteProviderProps {
93
111
  router: Router;
94
112
  announceNavigation?: boolean;
113
+ scrollRestoration?: ScrollRestorationOptions;
95
114
  }
96
115
  declare function RouterProvider(props: ParentProps<RouteProviderProps>): JSX.Element;
97
116
 
@@ -108,4 +127,4 @@ declare function createSignalFromSource<T>(source: RouterSource<T>): Accessor<T>
108
127
  declare function createStoreFromSource<T extends object>(source: RouterSource<T>): T;
109
128
 
110
129
  export { Link, RouteContext, RouteView, RouterContext, RouterErrorBoundary, RouterProvider, createSignalFromSource, createStoreFromSource, link, useNavigator, useRoute, useRouteNode, useRouteNodeStore, useRouteStore, useRouteUtils, useRouter, useRouterTransition };
111
- export type { LinkDirectiveOptions, LinkProps, RouteState, MatchProps as RouteViewMatchProps, NotFoundProps as RouteViewNotFoundProps, RouteViewProps, RouterErrorBoundaryProps };
130
+ export type { LinkDirectiveOptions, LinkProps, RouteState, MatchProps as RouteViewMatchProps, NotFoundProps as RouteViewNotFoundProps, RouteViewProps, SelfProps as RouteViewSelfProps, RouterErrorBoundaryProps };