@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
@@ -2,12 +2,13 @@ import { UNKNOWN_ROUTE } from "@real-router/core";
2
2
  import { startsWithSegment } from "@real-router/route-utils";
3
3
  import { Suspense } from "solid-js";
4
4
 
5
- import { MATCH_MARKER, NOT_FOUND_MARKER } from "./components";
5
+ import { MATCH_MARKER, NOT_FOUND_MARKER, SELF_MARKER } from "./components";
6
6
 
7
7
  import type {
8
8
  MatchMarker,
9
9
  NotFoundMarker,
10
10
  RouteViewMarker,
11
+ SelfMarker,
11
12
  } from "./components";
12
13
  import type { JSX } from "solid-js";
13
14
 
@@ -32,6 +33,15 @@ function isMatchMarker(value: unknown): value is MatchMarker {
32
33
  );
33
34
  }
34
35
 
36
+ function isSelfMarker(value: unknown): value is SelfMarker {
37
+ return (
38
+ value != null &&
39
+ typeof value === "object" &&
40
+ "$$type" in value &&
41
+ value.$$type === SELF_MARKER
42
+ );
43
+ }
44
+
35
45
  function isNotFoundMarker(value: unknown): value is NotFoundMarker {
36
46
  return (
37
47
  value != null &&
@@ -57,16 +67,56 @@ export function collectElements(
57
67
  return;
58
68
  }
59
69
 
60
- if (isMatchMarker(children) || isNotFoundMarker(children)) {
70
+ if (
71
+ isMatchMarker(children) ||
72
+ isSelfMarker(children) ||
73
+ isNotFoundMarker(children)
74
+ ) {
61
75
  result.push(children);
62
76
  }
63
77
  }
64
78
 
79
+ // child.children is a getter — read it INSIDE the JSX expression so Solid
80
+ // creates a reactive dependency. Pulling it into a variable freezes the
81
+ // value at template-build time and breaks Suspense fallback transitions
82
+ // (lazy() resolution).
83
+ function renderMatch(child: MatchMarker): JSX.Element {
84
+ return child.fallback === undefined ? (
85
+ child.children
86
+ ) : (
87
+ <Suspense fallback={child.fallback}>{child.children}</Suspense>
88
+ );
89
+ }
90
+
91
+ function renderSelf(self: SelfMarker): JSX.Element {
92
+ return self.fallback === undefined ? (
93
+ self.children
94
+ ) : (
95
+ <Suspense fallback={self.fallback}>{self.children}</Suspense>
96
+ );
97
+ }
98
+
99
+ function processMatchChild(
100
+ child: MatchMarker,
101
+ routeName: string,
102
+ nodeName: string,
103
+ ): JSX.Element | null {
104
+ const { segment, exact } = child;
105
+ const fullSegmentName = nodeName ? `${nodeName}.${segment}` : segment;
106
+
107
+ if (!isSegmentMatch(routeName, fullSegmentName, exact)) {
108
+ return null;
109
+ }
110
+
111
+ return renderMatch(child);
112
+ }
113
+
65
114
  export function buildRenderList(
66
115
  elements: RouteViewMarker[],
67
116
  routeName: string,
68
117
  nodeName: string,
69
118
  ): JSX.Element[] {
119
+ let selfMarker: SelfMarker | null = null;
70
120
  let notFoundChildren: JSX.Element | null = null;
71
121
  let activeMatchFound = false;
72
122
  const rendered: JSX.Element[] = [];
@@ -77,33 +127,29 @@ export function buildRenderList(
77
127
  continue;
78
128
  }
79
129
 
80
- if (activeMatchFound) {
130
+ if (isSelfMarker(child)) {
131
+ selfMarker ??= child;
81
132
  continue;
82
133
  }
83
134
 
84
- const { segment, exact, fallback } = child;
85
- const fullSegmentName = nodeName ? `${nodeName}.${segment}` : segment;
86
-
87
- if (!isSegmentMatch(routeName, fullSegmentName, exact)) {
135
+ if (activeMatchFound) {
88
136
  continue;
89
137
  }
90
138
 
91
- activeMatchFound = true;
92
- rendered.push(
93
- fallback === undefined ? (
94
- child.children
95
- ) : (
96
- <Suspense fallback={fallback}>{child.children}</Suspense>
97
- ),
98
- );
139
+ const matchRendered = processMatchChild(child, routeName, nodeName);
140
+
141
+ if (matchRendered !== null) {
142
+ activeMatchFound = true;
143
+ rendered.push(matchRendered);
144
+ }
99
145
  }
100
146
 
101
- if (
102
- !activeMatchFound &&
103
- routeName === UNKNOWN_ROUTE &&
104
- notFoundChildren !== null
105
- ) {
106
- rendered.push(notFoundChildren);
147
+ if (!activeMatchFound) {
148
+ if (selfMarker !== null && routeName === nodeName) {
149
+ rendered.push(renderSelf(selfMarker));
150
+ } else if (routeName === UNKNOWN_ROUTE && notFoundChildren !== null) {
151
+ rendered.push(notFoundChildren);
152
+ }
107
153
  }
108
154
 
109
155
  return rendered;
@@ -3,5 +3,6 @@ export { RouteView } from "./RouteView";
3
3
  export type {
4
4
  RouteViewProps,
5
5
  RouteViewMatchProps,
6
+ RouteViewSelfProps,
6
7
  RouteViewNotFoundProps,
7
8
  } from "./RouteView";
@@ -12,6 +12,13 @@ export interface MatchProps {
12
12
  readonly children: JSX.Element;
13
13
  }
14
14
 
15
+ export interface SelfProps {
16
+ /** Fallback content while children are suspended. */
17
+ readonly fallback?: JSX.Element;
18
+ /** Content to render when the active route name equals the parent RouteView's nodeName. */
19
+ readonly children: JSX.Element;
20
+ }
21
+
15
22
  export interface NotFoundProps {
16
23
  readonly children: JSX.Element;
17
24
  }
@@ -3,11 +3,7 @@ import { createEffect, onCleanup } from "solid-js";
3
3
 
4
4
  import { EMPTY_PARAMS, EMPTY_OPTIONS } from "../constants";
5
5
  import { createSignalFromSource } from "../createSignalFromSource";
6
- import {
7
- shouldNavigate,
8
- applyLinkA11y,
9
- buildHref,
10
- } from "../dom-utils/index.js";
6
+ import { shouldNavigate, applyLinkA11y, buildHref } from "../dom-utils";
11
7
  import { useRouter } from "../hooks/useRouter";
12
8
 
13
9
  import type { Params } from "@real-router/core";
package/src/index.tsx CHANGED
@@ -39,6 +39,7 @@ export type { LinkDirectiveOptions } from "./directives/link";
39
39
  export type {
40
40
  RouteViewProps,
41
41
  RouteViewMatchProps,
42
+ RouteViewSelfProps,
42
43
  RouteViewNotFoundProps,
43
44
  } from "./components/RouteView";
44
45