@octanejs/tanstack-router 0.2.6 → 0.2.8
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.
- package/README.md +48 -0
- package/package.json +4 -3
- package/src/Matches.tsrx +1 -1
- package/src/Transitioner.tsrx +3 -3
- package/src/compiled/Matches.tsrx +266 -0
- package/src/compiled/bindings.ts +40 -0
- package/src/compiled.ts +32 -0
- package/src/fileRoute.ts +3 -2
- package/src/frameworkTypes.ts +11 -8
- package/src/hookBindings.ts +396 -0
- package/src/hooks.ts +17 -374
- package/src/index.ts +2 -0
- package/src/lazyRouteComponent.ts +6 -50
- package/src/lazyRouteLoader.ts +49 -0
- package/src/route.ts +181 -0
- package/src/routerStateBinding.ts +41 -0
- package/src/useRouterState.ts +3 -35
package/README.md
CHANGED
|
@@ -134,3 +134,51 @@ package's `status.json`).
|
|
|
134
134
|
- **Native DOM events** — link callbacks receive browser events rather than React
|
|
135
135
|
synthetic events.
|
|
136
136
|
- Router devtools are distributed separately and are not part of this binding.
|
|
137
|
+
|
|
138
|
+
## Compiled code routes
|
|
139
|
+
|
|
140
|
+
Use `@octanejs/tanstack-router/compiled` for a tree whose selected route, pending,
|
|
141
|
+
error and not-found components are compiled Octane `@{ ... }` bodies. Its
|
|
142
|
+
`CompiledRouterProvider`, `CompiledOutlet`, and `lazyCompiledRouteComponent`
|
|
143
|
+
avoid retaining the descriptor renderer merely to select a route at runtime.
|
|
144
|
+
TanStack still owns the matching, loading, navigation, history and render
|
|
145
|
+
acknowledgements.
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
import {
|
|
149
|
+
BaseRootRoute, BaseRoute, createRouter, createBrowserHistory,
|
|
150
|
+
CompiledRouterProvider, CompiledOutlet, lazyCompiledRouteComponent, useParams,
|
|
151
|
+
} from '@octanejs/tanstack-router/compiled';
|
|
152
|
+
|
|
153
|
+
const root = new BaseRootRoute({ component: Layout });
|
|
154
|
+
const item = new BaseRoute({
|
|
155
|
+
getParentRoute: () => root,
|
|
156
|
+
path: 'items/$id',
|
|
157
|
+
component: lazyCompiledRouteComponent(() => import('./Item')),
|
|
158
|
+
});
|
|
159
|
+
const router = createRouter({
|
|
160
|
+
routeTree: root.addChildren([item]),
|
|
161
|
+
history: createBrowserHistory(),
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
function Layout() @{
|
|
165
|
+
<main><CompiledOutlet /></main>
|
|
166
|
+
}
|
|
167
|
+
function App() @{
|
|
168
|
+
<CompiledRouterProvider router={router} />
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Import read/navigation hooks (`useMatch`, `useParams`, `useSearch`,
|
|
173
|
+
`useLoaderData`, `useLoaderDeps`, `useRouteContext`, `useLocation`,
|
|
174
|
+
`useMatches`, `useParentMatches`, `useChildMatches`, `useNavigate`,
|
|
175
|
+
`useCanGoBack`, `useRouter`, and `useRouterState`) from the same `/compiled`
|
|
176
|
+
entry. It owns a separate pair of non-callable contexts. Base route factories
|
|
177
|
+
come directly from router-core: use the free hooks in the route components,
|
|
178
|
+
rather than route-bound hooks or `Route.Link` from the normal Octane entry.
|
|
179
|
+
|
|
180
|
+
The first compiled contract excludes `Wrap`, `InnerWrap`, and
|
|
181
|
+
`shellComponent`; the provider reports a diagnostic if they are configured.
|
|
182
|
+
For returned JSX, host strings, renderable wrappers or mixed route trees, retain
|
|
183
|
+
`RouterProvider`, `Outlet` and `lazyRouteComponent` from the ordinary entry.
|
|
184
|
+
SSR and client builds must select the same entry for a tree.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octanejs/tanstack-router",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"exports": {
|
|
38
38
|
".": "./src/index.ts",
|
|
39
39
|
"./history": "./src/history.ts",
|
|
40
|
+
"./compiled": "./src/compiled.ts",
|
|
40
41
|
"./ssr/server": {
|
|
41
42
|
"types": "./src/ssr/server.ts",
|
|
42
43
|
"default": "./src/ssr/server.ts"
|
|
@@ -58,13 +59,13 @@
|
|
|
58
59
|
"isbot": "^5.1.22"
|
|
59
60
|
},
|
|
60
61
|
"peerDependencies": {
|
|
61
|
-
"octane": "^0.
|
|
62
|
+
"octane": "^0.13.0"
|
|
62
63
|
},
|
|
63
64
|
"devDependencies": {
|
|
64
65
|
"@tanstack/react-router": "1.170.41",
|
|
65
66
|
"@tsrx/react": "^0.4.5",
|
|
66
67
|
"esbuild": "^0.28.1",
|
|
67
|
-
"octane": "0.
|
|
68
|
+
"octane": "0.13.6",
|
|
68
69
|
"react": "19.2.7",
|
|
69
70
|
"react-dom": "19.2.7",
|
|
70
71
|
"vitest": "^4.1.10"
|
package/src/Matches.tsrx
CHANGED
package/src/Transitioner.tsrx
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
// restoration, devtools) fire.
|
|
20
20
|
import { useLayoutEffect, useState, startTransition } from 'octane';
|
|
21
21
|
import { getLocationChangeInfo, trimPathRight } from '@tanstack/router-core';
|
|
22
|
-
import {
|
|
22
|
+
import type { AnyRouter } from '@tanstack/router-core';
|
|
23
23
|
|
|
24
24
|
// Resolve the pending render acknowledgement with whether the expected matches
|
|
25
25
|
// rendered, then clear the slot. `owner` is `router._rendered`: `[expected, resolve]`.
|
|
@@ -29,8 +29,8 @@ export function settleOwner(owner: Array<any>, rendered: boolean) {
|
|
|
29
29
|
settle?.(rendered);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export function useTransitioner() {
|
|
33
|
-
const router =
|
|
32
|
+
export function useTransitioner(routerInstance: AnyRouter) {
|
|
33
|
+
const router = routerInstance as any;
|
|
34
34
|
const [, forceRender] = useState<object>();
|
|
35
35
|
|
|
36
36
|
const acknowledgement: Array<any> = (router._rendered ??= []);
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CompiledOutlet as CompiledComponent,
|
|
3
|
+
CompiledContext,
|
|
4
|
+
useContext,
|
|
5
|
+
useLayoutEffect,
|
|
6
|
+
useRef,
|
|
7
|
+
} from 'octane';
|
|
8
|
+
import type { NotFoundError } from '@tanstack/router-core';
|
|
9
|
+
import { hasKeys, isNotFound, rootRouteId, setupScrollRestoration } from '@tanstack/router-core';
|
|
10
|
+
import { getScrollRestorationScriptForRouter } from '@tanstack/router-core/scroll-restoration-script';
|
|
11
|
+
import { isServer } from '@tanstack/router-core/isServer';
|
|
12
|
+
import { routerContext, matchContext, useRouter } from './bindings';
|
|
13
|
+
import { useStore } from '../useStore';
|
|
14
|
+
import { useTransitioner, settleOwner } from '../Transitioner.tsrx';
|
|
15
|
+
import { useHydrated } from '../ClientOnly.tsrx';
|
|
16
|
+
import { ErrorComponent } from '../CatchBoundary.tsrx';
|
|
17
|
+
import { createLazyRouteLoader } from '../lazyRouteLoader';
|
|
18
|
+
import type { RouterProps } from '../RouterProvider.tsrx';
|
|
19
|
+
|
|
20
|
+
export function CompiledRouterProvider(props: RouterProps) @{
|
|
21
|
+
const { router, ...rest } = props;
|
|
22
|
+
if (hasKeys(rest)) {
|
|
23
|
+
router.update({
|
|
24
|
+
...router.options,
|
|
25
|
+
...rest,
|
|
26
|
+
context: { ...router.options.context, ...rest.context },
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
if (router.options.Wrap || router.options.InnerWrap) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
'CompiledRouterProvider does not accept Wrap or InnerWrap. Use RouterProvider for renderable wrappers.',
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
<CompiledContext context={routerContext} value={router}>
|
|
35
|
+
<CompiledMatches />
|
|
36
|
+
</CompiledContext>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function CompiledMatches() @{
|
|
40
|
+
const router = useRouter();
|
|
41
|
+
const rootRoute = (router.routesById as any)[rootRouteId];
|
|
42
|
+
useLayoutEffect(() => {
|
|
43
|
+
if (router.options.scrollRestoration) setupScrollRestoration(router);
|
|
44
|
+
}, [router]);
|
|
45
|
+
useTransitioner(router);
|
|
46
|
+
@try {
|
|
47
|
+
<CompiledMatchesInner />
|
|
48
|
+
} @pending {
|
|
49
|
+
<CompiledPending route={rootRoute} />
|
|
50
|
+
} @catch (error, reset) {
|
|
51
|
+
if (router.options.disableGlobalCatchBoundary) throw error;
|
|
52
|
+
<CompiledFailure error={error} reset={reset} route={rootRoute} global={true} />
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function CompiledMatchesInner() @{
|
|
57
|
+
const router = useRouter();
|
|
58
|
+
const acknowledgement: Array<any> = ((router as any)._rendered ??= []);
|
|
59
|
+
const matches = useStore(router.stores.matches, (m: any) => acknowledgement[0] ?? m);
|
|
60
|
+
const rootMatch = matches[0];
|
|
61
|
+
useLayoutEffect(() => {
|
|
62
|
+
if (acknowledgement[0] === matches) settleOwner(acknowledgement, true);
|
|
63
|
+
}, [acknowledgement, matches]);
|
|
64
|
+
@if (rootMatch) {
|
|
65
|
+
<CompiledMatch routeId={rootMatch.routeId} />
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function CompiledMatch(props: { routeId: string }) @{
|
|
70
|
+
const router = useRouter();
|
|
71
|
+
const store = router.stores.getMatchStore(props.routeId);
|
|
72
|
+
const ssr = useStore(store, (match: any) => match.ssr);
|
|
73
|
+
const route = (router.routesById as Record<string, any>)[props.routeId];
|
|
74
|
+
if (route.isRoot && route.options.shellComponent) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
'CompiledRouterProvider does not accept shellComponent. Use RouterProvider for renderable document shells.',
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
const pending = route.options.pendingComponent ?? router.options.defaultPendingComponent;
|
|
80
|
+
const errorComponent = route.options.errorComponent ?? router.options.defaultErrorComponent;
|
|
81
|
+
const noSsr = ssr === false || ssr === 'data-only';
|
|
82
|
+
const hasSuspense =
|
|
83
|
+
(!route.isRoot || route.options.wrapInSuspense || noSsr) &&
|
|
84
|
+
((route.options.wrapInSuspense ?? pending ?? errorComponent?.preload) || noSsr);
|
|
85
|
+
<CompiledContext context={matchContext} value={props.routeId}>
|
|
86
|
+
@if (hasSuspense) {
|
|
87
|
+
@try {
|
|
88
|
+
<CompiledMatchContent route={route} routeId={props.routeId} noSsr={noSsr} />
|
|
89
|
+
} @pending {
|
|
90
|
+
<CompiledPending route={route} />
|
|
91
|
+
}
|
|
92
|
+
} @else {
|
|
93
|
+
<CompiledMatchContent route={route} routeId={props.routeId} noSsr={noSsr} />
|
|
94
|
+
}
|
|
95
|
+
@if (route.parentRoute?.id === rootRouteId && router.options.scrollRestoration) {
|
|
96
|
+
<CompiledScrollRestoration />
|
|
97
|
+
}
|
|
98
|
+
</CompiledContext>
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Without a configured Suspense boundary, both lazy imports and loader promises
|
|
102
|
+
// pass through to the next ancestor boundary. The match still owns its errors.
|
|
103
|
+
function CompiledMatchContent(props: { route: any; routeId: string; noSsr: boolean }) @{
|
|
104
|
+
@try {
|
|
105
|
+
<CompiledMatchInner routeId={props.routeId} noSsr={props.noSsr} />
|
|
106
|
+
} @catch (error, reset) {
|
|
107
|
+
<CompiledFailure error={error} reset={reset} route={props.route} />
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function CompiledMatchInner(props: { routeId: string; noSsr: boolean }) @{
|
|
112
|
+
const router = useRouter();
|
|
113
|
+
const match = useStore(router.stores.getMatchStore(props.routeId), (m: any) => m);
|
|
114
|
+
const route = (router.routesById as Record<string, any>)[props.routeId];
|
|
115
|
+
const hydrated = useHydrated();
|
|
116
|
+
const Comp = route.options.component ?? router.options.defaultComponent;
|
|
117
|
+
const remountFn = route.options.remountDeps ?? router.options.defaultRemountDeps;
|
|
118
|
+
const remountDeps = remountFn?.({
|
|
119
|
+
routeId: props.routeId,
|
|
120
|
+
loaderDeps: match.loaderDeps,
|
|
121
|
+
params: match._strictParams,
|
|
122
|
+
search: match._strictSearch,
|
|
123
|
+
});
|
|
124
|
+
const key = remountDeps ? JSON.stringify(remountDeps) : undefined;
|
|
125
|
+
if (match.status === 'pending' && !props.noSsr && (router as any)._tx) {
|
|
126
|
+
throw (router as any)._tx[5];
|
|
127
|
+
}
|
|
128
|
+
@if ((props.noSsr && !hydrated) || match.status === 'pending') {
|
|
129
|
+
<CompiledPending route={route} />
|
|
130
|
+
} @else if (match.status === 'notFound') {
|
|
131
|
+
<CompiledNotFound route={route} error={match.error} />
|
|
132
|
+
} @else if (match.status === 'error') {
|
|
133
|
+
@if (isServer ?? (router as any).isServer) {
|
|
134
|
+
<CompiledComponent
|
|
135
|
+
component={
|
|
136
|
+
route.options.errorComponent ?? router.options.defaultErrorComponent ?? ErrorComponent
|
|
137
|
+
}
|
|
138
|
+
props={{ error: match.error, reset: undefined, info: { componentStack: '' } }}
|
|
139
|
+
/>
|
|
140
|
+
} @else {
|
|
141
|
+
throw match.error;
|
|
142
|
+
<></>
|
|
143
|
+
}
|
|
144
|
+
} @else if (Comp) {
|
|
145
|
+
<CompiledComponent key={key} component={Comp} props={{}} />
|
|
146
|
+
} @else {
|
|
147
|
+
<CompiledOutlet />
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Reads exactly the next TanStack match, preserving nearest-match contexts and
|
|
152
|
+
// fuzzy/root not-found placement. This is distinct from octane's component outlet.
|
|
153
|
+
export function CompiledOutlet() @{
|
|
154
|
+
const router = useRouter();
|
|
155
|
+
const routeId = useContext(matchContext)!;
|
|
156
|
+
const store = router.stores.getMatchStore(routeId);
|
|
157
|
+
const notFound = useStore(
|
|
158
|
+
store,
|
|
159
|
+
(m: any) => ({ global: !!m?._notFound, error: m?.error }),
|
|
160
|
+
(a, b) => a.global === b.global && a.error === b.error,
|
|
161
|
+
);
|
|
162
|
+
const childId = useStore(router.stores.ids, (ids: Array<string>) => {
|
|
163
|
+
const i = ids.indexOf(routeId);
|
|
164
|
+
return i >= 0 ? ids[i + 1] : undefined;
|
|
165
|
+
});
|
|
166
|
+
@if (notFound.global) {
|
|
167
|
+
<CompiledNotFound route={(router.routesById as any)[routeId]} error={notFound.error} />
|
|
168
|
+
} @else if (childId) {
|
|
169
|
+
@if (routeId === rootRouteId) {
|
|
170
|
+
@try {
|
|
171
|
+
<CompiledMatch routeId={childId} />
|
|
172
|
+
} @pending {
|
|
173
|
+
<CompiledPending />
|
|
174
|
+
}
|
|
175
|
+
} @else {
|
|
176
|
+
<CompiledMatch routeId={childId} />
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function CompiledPending(props: { route?: any }) @{
|
|
182
|
+
const router = useRouter();
|
|
183
|
+
const Pending = props.route?.options.pendingComponent ?? router.options.defaultPendingComponent;
|
|
184
|
+
@if (Pending) {
|
|
185
|
+
<CompiledComponent component={Pending} props={{}} />
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function CompiledNotFound(props: { route: any; error?: NotFoundError }) @{
|
|
190
|
+
const router = useRouter();
|
|
191
|
+
const NotFound = props.route.options.notFoundComponent ?? router.options.defaultNotFoundComponent;
|
|
192
|
+
@if (NotFound) {
|
|
193
|
+
<CompiledComponent component={NotFound} props={props.error ?? {}} />
|
|
194
|
+
} @else {
|
|
195
|
+
<p>Not Found</p>
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function CompiledFailure(props: { error: any; reset: () => void; route: any; global?: boolean }) @{
|
|
200
|
+
const router = useRouter();
|
|
201
|
+
const errorComponent = props.global
|
|
202
|
+
? ErrorComponent
|
|
203
|
+
: (props.route.options.errorComponent ?? router.options.defaultErrorComponent);
|
|
204
|
+
const notFoundComponent = props.route.isRoot
|
|
205
|
+
? (props.route.options.notFoundComponent ?? router.options.notFoundRoute?.options.component)
|
|
206
|
+
: props.route.options.notFoundComponent;
|
|
207
|
+
const isMissing = isNotFound(props.error);
|
|
208
|
+
if (isMissing) {
|
|
209
|
+
const missing = props.error as NotFoundError;
|
|
210
|
+
missing.routeId ??= props.route.id;
|
|
211
|
+
if (!notFoundComponent || missing.routeId !== props.route.id) throw missing;
|
|
212
|
+
} else if (!errorComponent) {
|
|
213
|
+
throw props.error;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Report an error only at the boundary that owns it and retry after its
|
|
217
|
+
// TanStack match identity changes, just like the normal binding.
|
|
218
|
+
const reported = useRef<unknown>(null);
|
|
219
|
+
if (!isMissing && !props.global && reported.current !== props.error) {
|
|
220
|
+
reported.current = props.error;
|
|
221
|
+
const onCatch = props.route.options.onCatch ?? router.options.defaultOnCatch;
|
|
222
|
+
onCatch?.(props.error, { componentStack: '' });
|
|
223
|
+
}
|
|
224
|
+
const store = router.stores.getMatchStore(props.route.id);
|
|
225
|
+
const match = useStore(store, (m: any) => m);
|
|
226
|
+
const firstMatch = useRef(match);
|
|
227
|
+
useLayoutEffect(() => {
|
|
228
|
+
if (firstMatch.current !== match) {
|
|
229
|
+
firstMatch.current = match;
|
|
230
|
+
props.reset();
|
|
231
|
+
}
|
|
232
|
+
}, [match]);
|
|
233
|
+
|
|
234
|
+
@if (isMissing) {
|
|
235
|
+
<CompiledComponent component={notFoundComponent} props={props.error} />
|
|
236
|
+
} @else {
|
|
237
|
+
<CompiledComponent
|
|
238
|
+
component={errorComponent}
|
|
239
|
+
props={{ error: props.error, reset: props.reset, info: { componentStack: '' } }}
|
|
240
|
+
/>
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function CompiledScrollRestoration() @{
|
|
245
|
+
const router = useRouter();
|
|
246
|
+
const hydrated = useHydrated();
|
|
247
|
+
const option = router.options.scrollRestoration;
|
|
248
|
+
const script = getScrollRestorationScriptForRouter(router);
|
|
249
|
+
const rendersScript = typeof option !== 'function' || option({ location: router.latestLocation });
|
|
250
|
+
@if ((script !== null || rendersScript) && ((isServer ?? router.isServer) || !hydrated)) {
|
|
251
|
+
<script
|
|
252
|
+
nonce={router.options.ssr?.nonce}
|
|
253
|
+
suppressHydrationWarning
|
|
254
|
+
dangerouslySetInnerHTML={{ __html: script ?? '' }}
|
|
255
|
+
/>
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export function lazyCompiledRouteComponent(importer: () => Promise<any>, exportName?: string) {
|
|
260
|
+
const loader = createLazyRouteLoader(importer, exportName);
|
|
261
|
+
function Lazy(props: any) @{
|
|
262
|
+
<CompiledComponent component={loader.read()} props={props} />
|
|
263
|
+
}
|
|
264
|
+
Lazy.preload = loader.preload;
|
|
265
|
+
return Lazy;
|
|
266
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { createCompiledContext, useContext } from 'octane';
|
|
2
|
+
import type { AnyRouter, RegisteredRouter } from '@tanstack/router-core';
|
|
3
|
+
import { createRouterHooks } from '../hookBindings';
|
|
4
|
+
import { createUseRouterState } from '../routerStateBinding';
|
|
5
|
+
|
|
6
|
+
// The normal contexts remain callable providers. These contexts belong only to
|
|
7
|
+
// the opt-in compiled tree so that using it never imports a generic provider.
|
|
8
|
+
export const routerContext = createCompiledContext<AnyRouter | undefined>(undefined);
|
|
9
|
+
export const matchContext = createCompiledContext<string | undefined>(undefined);
|
|
10
|
+
|
|
11
|
+
export function useRouter<TRouter extends AnyRouter = RegisteredRouter>(opts?: {
|
|
12
|
+
router?: TRouter;
|
|
13
|
+
warn?: boolean;
|
|
14
|
+
}): TRouter;
|
|
15
|
+
export function useRouter(...args: unknown[]): AnyRouter {
|
|
16
|
+
const opts = (args.length && typeof args[0] !== 'symbol' ? args[0] : undefined) as
|
|
17
|
+
{ router?: AnyRouter; warn?: boolean } | undefined;
|
|
18
|
+
const router = opts?.router ?? useContext(routerContext);
|
|
19
|
+
if (!router && opts?.warn !== false) {
|
|
20
|
+
throw new Error('Use compiled router hooks inside <CompiledRouterProvider>.');
|
|
21
|
+
}
|
|
22
|
+
return router as AnyRouter;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const {
|
|
26
|
+
useMatch,
|
|
27
|
+
useParams,
|
|
28
|
+
useSearch,
|
|
29
|
+
useLoaderData,
|
|
30
|
+
useLoaderDeps,
|
|
31
|
+
useRouteContext,
|
|
32
|
+
useLocation,
|
|
33
|
+
useMatches,
|
|
34
|
+
useParentMatches,
|
|
35
|
+
useChildMatches,
|
|
36
|
+
useNavigate,
|
|
37
|
+
useCanGoBack,
|
|
38
|
+
} = createRouterHooks(useRouter, () => useContext(matchContext));
|
|
39
|
+
|
|
40
|
+
export const useRouterState = createUseRouterState(useRouter);
|
package/src/compiled.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Opt-in source-owned renderer for code routes with compiled bodies only.
|
|
2
|
+
import './frameworkTypes';
|
|
3
|
+
export * from '@tanstack/router-core';
|
|
4
|
+
export { Router, createRouter } from './router';
|
|
5
|
+
export {
|
|
6
|
+
createHistory,
|
|
7
|
+
createBrowserHistory,
|
|
8
|
+
createHashHistory,
|
|
9
|
+
createMemoryHistory,
|
|
10
|
+
} from './history';
|
|
11
|
+
export {
|
|
12
|
+
useRouter,
|
|
13
|
+
useRouterState,
|
|
14
|
+
useMatch,
|
|
15
|
+
useParams,
|
|
16
|
+
useSearch,
|
|
17
|
+
useLoaderData,
|
|
18
|
+
useLoaderDeps,
|
|
19
|
+
useRouteContext,
|
|
20
|
+
useLocation,
|
|
21
|
+
useMatches,
|
|
22
|
+
useParentMatches,
|
|
23
|
+
useChildMatches,
|
|
24
|
+
useNavigate,
|
|
25
|
+
useCanGoBack,
|
|
26
|
+
} from './compiled/bindings';
|
|
27
|
+
export type { UseRouterStateOptions, UseRouterStateResult } from './routerStateBinding';
|
|
28
|
+
export {
|
|
29
|
+
CompiledRouterProvider,
|
|
30
|
+
CompiledOutlet,
|
|
31
|
+
lazyCompiledRouteComponent,
|
|
32
|
+
} from './compiled/Matches.tsrx';
|
package/src/fileRoute.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createRoute } from './route';
|
|
2
|
+
import type { Route } from './route';
|
|
2
3
|
import {
|
|
3
4
|
useLoaderData,
|
|
4
5
|
useLoaderDeps,
|
|
@@ -22,7 +23,6 @@ import type {
|
|
|
22
23
|
Register,
|
|
23
24
|
RegisteredRouter,
|
|
24
25
|
ResolveParams,
|
|
25
|
-
Route,
|
|
26
26
|
RouteById,
|
|
27
27
|
RouteConstraints,
|
|
28
28
|
RouteIds,
|
|
@@ -268,7 +268,8 @@ export function createLazyRoute<
|
|
|
268
268
|
|
|
269
269
|
export function createLazyFileRoute<
|
|
270
270
|
TFilePath extends keyof FileRoutesByPath,
|
|
271
|
-
TRoute extends FileRoutesByPath[TFilePath]['preLoaderRoute']
|
|
271
|
+
TRoute extends FileRoutesByPath[TFilePath]['preLoaderRoute'] & AnyRoute =
|
|
272
|
+
FileRoutesByPath[TFilePath]['preLoaderRoute'],
|
|
272
273
|
>(id: TFilePath): (opts: LazyRouteOptions) => LazyRoute<TRoute> {
|
|
273
274
|
if (typeof id === 'object') {
|
|
274
275
|
return new LazyRoute<TRoute>(id) as any;
|
package/src/frameworkTypes.ts
CHANGED
|
@@ -30,13 +30,16 @@ declare module '@tanstack/router-core' {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
interface RouteExtensions<in out TId extends string, in out TFullPath extends string> {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
// Core base routes are also valid in compiled trees and do not own bound
|
|
34
|
+
// renderer hooks. The ordinary binding's concrete Route classes provide
|
|
35
|
+
// each of these members as required properties.
|
|
36
|
+
useMatch?: UseMatchRoute<TId>;
|
|
37
|
+
useRouteContext?: UseRouteContextRoute<TId>;
|
|
38
|
+
useSearch?: UseSearchRoute<TId>;
|
|
39
|
+
useParams?: UseParamsRoute<TId>;
|
|
40
|
+
useLoaderDeps?: UseLoaderDepsRoute<TId>;
|
|
41
|
+
useLoaderData?: UseLoaderDataRoute<TId>;
|
|
42
|
+
useNavigate?: () => UseNavigateResult<TFullPath>;
|
|
43
|
+
Link?: LinkComponentRoute<TFullPath>;
|
|
41
44
|
}
|
|
42
45
|
}
|