@tanstack/solid-router 1.121.0-alpha.27 → 1.121.0-alpha.28

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 (265) hide show
  1. package/dist/cjs/Asset.cjs +65 -21
  2. package/dist/cjs/Asset.cjs.map +1 -1
  3. package/dist/cjs/Asset.d.cts +2 -1
  4. package/dist/cjs/CatchBoundary.cjs +14 -15
  5. package/dist/cjs/CatchBoundary.cjs.map +1 -1
  6. package/dist/cjs/ClientOnly.cjs +12 -14
  7. package/dist/cjs/ClientOnly.cjs.map +1 -1
  8. package/dist/cjs/ClientOnly.d.cts +0 -20
  9. package/dist/cjs/HeadContent.cjs +28 -23
  10. package/dist/cjs/HeadContent.cjs.map +1 -1
  11. package/dist/cjs/Match.cjs +167 -141
  12. package/dist/cjs/Match.cjs.map +1 -1
  13. package/dist/cjs/Matches.cjs +26 -24
  14. package/dist/cjs/Matches.cjs.map +1 -1
  15. package/dist/cjs/Matches.d.cts +1 -0
  16. package/dist/cjs/RouterProvider.cjs +5 -5
  17. package/dist/cjs/RouterProvider.cjs.map +1 -1
  18. package/dist/cjs/SafeFragment.cjs +2 -2
  19. package/dist/cjs/SafeFragment.cjs.map +1 -1
  20. package/dist/cjs/ScriptOnce.cjs +4 -9
  21. package/dist/cjs/ScriptOnce.cjs.map +1 -1
  22. package/dist/cjs/ScriptOnce.d.cts +1 -1
  23. package/dist/cjs/Scripts.cjs +9 -13
  24. package/dist/cjs/Scripts.cjs.map +1 -1
  25. package/dist/cjs/ScrollRestoration.cjs +3 -4
  26. package/dist/cjs/ScrollRestoration.cjs.map +1 -1
  27. package/dist/cjs/Transitioner.cjs +9 -8
  28. package/dist/cjs/Transitioner.cjs.map +1 -1
  29. package/dist/cjs/awaited.cjs +2 -2
  30. package/dist/cjs/awaited.cjs.map +1 -1
  31. package/dist/cjs/fileRoute.cjs +5 -5
  32. package/dist/cjs/fileRoute.cjs.map +1 -1
  33. package/dist/cjs/index.cjs +0 -12
  34. package/dist/cjs/index.cjs.map +1 -1
  35. package/dist/cjs/index.d.cts +3 -6
  36. package/dist/cjs/lazyRouteComponent.cjs +6 -26
  37. package/dist/cjs/lazyRouteComponent.cjs.map +1 -1
  38. package/dist/cjs/lazyRouteComponent.d.cts +1 -1
  39. package/dist/cjs/link.cjs +37 -31
  40. package/dist/cjs/link.cjs.map +1 -1
  41. package/dist/cjs/not-found.cjs +5 -7
  42. package/dist/cjs/not-found.cjs.map +1 -1
  43. package/dist/cjs/renderRouteNotFound.cjs +4 -4
  44. package/dist/cjs/renderRouteNotFound.cjs.map +1 -1
  45. package/dist/cjs/route.cjs +16 -16
  46. package/dist/cjs/route.cjs.map +1 -1
  47. package/dist/cjs/route.d.cts +14 -5
  48. package/dist/cjs/router.cjs.map +1 -1
  49. package/dist/cjs/routerContext.cjs.map +1 -1
  50. package/dist/cjs/scroll-restoration.cjs +12 -6
  51. package/dist/cjs/scroll-restoration.cjs.map +1 -1
  52. package/dist/cjs/ssr/RouterClient.cjs +45 -0
  53. package/dist/cjs/ssr/RouterClient.cjs.map +1 -0
  54. package/dist/cjs/ssr/RouterClient.d.cts +4 -0
  55. package/dist/cjs/ssr/RouterServer.cjs +56 -0
  56. package/dist/cjs/ssr/RouterServer.cjs.map +1 -0
  57. package/dist/cjs/ssr/RouterServer.d.cts +5 -0
  58. package/dist/cjs/ssr/client.cjs +5 -0
  59. package/dist/cjs/ssr/client.cjs.map +1 -0
  60. package/dist/cjs/ssr/client.d.cts +1 -0
  61. package/dist/cjs/ssr/defaultRenderHandler.cjs +18 -0
  62. package/dist/cjs/ssr/defaultRenderHandler.cjs.map +1 -0
  63. package/dist/cjs/ssr/defaultRenderHandler.d.cts +1 -0
  64. package/dist/cjs/ssr/defaultStreamHandler.cjs +20 -0
  65. package/dist/cjs/ssr/defaultStreamHandler.cjs.map +1 -0
  66. package/dist/cjs/ssr/defaultStreamHandler.d.cts +1 -0
  67. package/dist/cjs/ssr/renderRouterToStream.cjs +45 -0
  68. package/dist/cjs/ssr/renderRouterToStream.cjs.map +1 -0
  69. package/dist/cjs/ssr/renderRouterToStream.d.cts +8 -0
  70. package/dist/cjs/ssr/renderRouterToString.cjs +43 -0
  71. package/dist/cjs/ssr/renderRouterToString.cjs.map +1 -0
  72. package/dist/cjs/ssr/renderRouterToString.d.cts +7 -0
  73. package/dist/cjs/ssr/server.cjs +20 -0
  74. package/dist/cjs/ssr/server.cjs.map +1 -0
  75. package/dist/cjs/ssr/server.d.cts +6 -0
  76. package/dist/cjs/useBlocker.cjs +41 -35
  77. package/dist/cjs/useBlocker.cjs.map +1 -1
  78. package/dist/cjs/useCanGoBack.cjs.map +1 -1
  79. package/dist/cjs/useLoaderData.cjs.map +1 -1
  80. package/dist/cjs/useLoaderDeps.cjs.map +1 -1
  81. package/dist/cjs/useLocation.cjs +1 -1
  82. package/dist/cjs/useLocation.cjs.map +1 -1
  83. package/dist/cjs/useMatch.cjs.map +1 -1
  84. package/dist/cjs/useNavigate.cjs +9 -3
  85. package/dist/cjs/useNavigate.cjs.map +1 -1
  86. package/dist/cjs/useParams.cjs.map +1 -1
  87. package/dist/cjs/useRouter.cjs +1 -1
  88. package/dist/cjs/useRouter.cjs.map +1 -1
  89. package/dist/cjs/useRouterState.cjs +3 -3
  90. package/dist/cjs/useRouterState.cjs.map +1 -1
  91. package/dist/cjs/useSearch.cjs.map +1 -1
  92. package/dist/cjs/utils.cjs +1 -1
  93. package/dist/cjs/utils.cjs.map +1 -1
  94. package/dist/esm/Asset.d.ts +2 -1
  95. package/dist/esm/Asset.js +60 -16
  96. package/dist/esm/Asset.js.map +1 -1
  97. package/dist/esm/CatchBoundary.js +1 -2
  98. package/dist/esm/CatchBoundary.js.map +1 -1
  99. package/dist/esm/ClientOnly.d.ts +0 -20
  100. package/dist/esm/ClientOnly.js +11 -13
  101. package/dist/esm/ClientOnly.js.map +1 -1
  102. package/dist/esm/HeadContent.js +23 -18
  103. package/dist/esm/HeadContent.js.map +1 -1
  104. package/dist/esm/Match.js +148 -122
  105. package/dist/esm/Match.js.map +1 -1
  106. package/dist/esm/Matches.d.ts +1 -0
  107. package/dist/esm/Matches.js +18 -16
  108. package/dist/esm/Matches.js.map +1 -1
  109. package/dist/esm/RouterProvider.js.map +1 -1
  110. package/dist/esm/SafeFragment.js.map +1 -1
  111. package/dist/esm/ScriptOnce.d.ts +1 -1
  112. package/dist/esm/ScriptOnce.js +2 -7
  113. package/dist/esm/ScriptOnce.js.map +1 -1
  114. package/dist/esm/Scripts.js +7 -11
  115. package/dist/esm/Scripts.js.map +1 -1
  116. package/dist/esm/ScrollRestoration.js +3 -4
  117. package/dist/esm/ScrollRestoration.js.map +1 -1
  118. package/dist/esm/Transitioner.js +9 -8
  119. package/dist/esm/Transitioner.js.map +1 -1
  120. package/dist/esm/awaited.js.map +1 -1
  121. package/dist/esm/fileRoute.js +5 -5
  122. package/dist/esm/fileRoute.js.map +1 -1
  123. package/dist/esm/index.d.ts +3 -6
  124. package/dist/esm/index.js +2 -8
  125. package/dist/esm/index.js.map +1 -1
  126. package/dist/esm/lazyRouteComponent.d.ts +1 -1
  127. package/dist/esm/lazyRouteComponent.js +2 -22
  128. package/dist/esm/lazyRouteComponent.js.map +1 -1
  129. package/dist/esm/link.js +34 -28
  130. package/dist/esm/link.js.map +1 -1
  131. package/dist/esm/not-found.js +2 -4
  132. package/dist/esm/not-found.js.map +1 -1
  133. package/dist/esm/renderRouteNotFound.js.map +1 -1
  134. package/dist/esm/route.d.ts +14 -5
  135. package/dist/esm/route.js +12 -12
  136. package/dist/esm/route.js.map +1 -1
  137. package/dist/esm/router.js.map +1 -1
  138. package/dist/esm/routerContext.js.map +1 -1
  139. package/dist/esm/scroll-restoration.js +10 -4
  140. package/dist/esm/scroll-restoration.js.map +1 -1
  141. package/dist/esm/ssr/RouterClient.d.ts +4 -0
  142. package/dist/esm/ssr/RouterClient.js +45 -0
  143. package/dist/esm/ssr/RouterClient.js.map +1 -0
  144. package/dist/esm/ssr/RouterServer.d.ts +5 -0
  145. package/dist/esm/ssr/RouterServer.js +56 -0
  146. package/dist/esm/ssr/RouterServer.js.map +1 -0
  147. package/dist/esm/ssr/client.d.ts +1 -0
  148. package/dist/esm/ssr/client.js +5 -0
  149. package/dist/esm/ssr/client.js.map +1 -0
  150. package/dist/esm/ssr/defaultRenderHandler.d.ts +1 -0
  151. package/dist/esm/ssr/defaultRenderHandler.js +18 -0
  152. package/dist/esm/ssr/defaultRenderHandler.js.map +1 -0
  153. package/dist/esm/ssr/defaultStreamHandler.d.ts +1 -0
  154. package/dist/esm/ssr/defaultStreamHandler.js +20 -0
  155. package/dist/esm/ssr/defaultStreamHandler.js.map +1 -0
  156. package/dist/esm/ssr/renderRouterToStream.d.ts +8 -0
  157. package/dist/esm/ssr/renderRouterToStream.js +28 -0
  158. package/dist/esm/ssr/renderRouterToStream.js.map +1 -0
  159. package/dist/esm/ssr/renderRouterToString.d.ts +7 -0
  160. package/dist/esm/ssr/renderRouterToString.js +26 -0
  161. package/dist/esm/ssr/renderRouterToString.js.map +1 -0
  162. package/dist/esm/ssr/server.d.ts +6 -0
  163. package/dist/esm/ssr/server.js +14 -0
  164. package/dist/esm/ssr/server.js.map +1 -0
  165. package/dist/esm/useBlocker.js +41 -35
  166. package/dist/esm/useBlocker.js.map +1 -1
  167. package/dist/esm/useCanGoBack.js.map +1 -1
  168. package/dist/esm/useLoaderData.js.map +1 -1
  169. package/dist/esm/useLoaderDeps.js.map +1 -1
  170. package/dist/esm/useLocation.js +1 -1
  171. package/dist/esm/useLocation.js.map +1 -1
  172. package/dist/esm/useMatch.js.map +1 -1
  173. package/dist/esm/useNavigate.js +9 -3
  174. package/dist/esm/useNavigate.js.map +1 -1
  175. package/dist/esm/useParams.js.map +1 -1
  176. package/dist/esm/useRouter.js +1 -1
  177. package/dist/esm/useRouter.js.map +1 -1
  178. package/dist/esm/useRouterState.js +3 -3
  179. package/dist/esm/useRouterState.js.map +1 -1
  180. package/dist/esm/useSearch.js.map +1 -1
  181. package/dist/esm/utils.js +1 -1
  182. package/dist/esm/utils.js.map +1 -1
  183. package/dist/source/Asset.d.ts +2 -1
  184. package/dist/source/Asset.jsx +45 -7
  185. package/dist/source/Asset.jsx.map +1 -1
  186. package/dist/source/ClientOnly.d.ts +0 -20
  187. package/dist/source/ClientOnly.jsx +3 -29
  188. package/dist/source/ClientOnly.jsx.map +1 -1
  189. package/dist/source/HeadContent.jsx +13 -0
  190. package/dist/source/HeadContent.jsx.map +1 -1
  191. package/dist/source/Match.jsx +74 -61
  192. package/dist/source/Match.jsx.map +1 -1
  193. package/dist/source/Matches.d.ts +1 -0
  194. package/dist/source/Matches.jsx +14 -11
  195. package/dist/source/Matches.jsx.map +1 -1
  196. package/dist/source/ScriptOnce.d.ts +1 -1
  197. package/dist/source/ScriptOnce.jsx +2 -12
  198. package/dist/source/ScriptOnce.jsx.map +1 -1
  199. package/dist/source/Transitioner.jsx +8 -8
  200. package/dist/source/Transitioner.jsx.map +1 -1
  201. package/dist/source/index.d.ts +3 -6
  202. package/dist/source/index.jsx +1 -4
  203. package/dist/source/index.jsx.map +1 -1
  204. package/dist/source/lazyRouteComponent.d.ts +1 -1
  205. package/dist/source/lazyRouteComponent.jsx +7 -21
  206. package/dist/source/lazyRouteComponent.jsx.map +1 -1
  207. package/dist/source/link.jsx +22 -17
  208. package/dist/source/link.jsx.map +1 -1
  209. package/dist/source/not-found.jsx.map +1 -1
  210. package/dist/source/route.d.ts +14 -5
  211. package/dist/source/route.jsx.map +1 -1
  212. package/dist/source/scroll-restoration.jsx +9 -2
  213. package/dist/source/scroll-restoration.jsx.map +1 -1
  214. package/dist/source/ssr/RouterClient.d.ts +4 -0
  215. package/dist/source/ssr/RouterClient.jsx +28 -0
  216. package/dist/source/ssr/RouterClient.jsx.map +1 -0
  217. package/dist/source/ssr/RouterServer.d.ts +5 -0
  218. package/dist/source/ssr/RouterServer.jsx +38 -0
  219. package/dist/source/ssr/RouterServer.jsx.map +1 -0
  220. package/dist/source/ssr/client.d.ts +1 -0
  221. package/dist/source/ssr/client.js +2 -0
  222. package/dist/source/ssr/client.js.map +1 -0
  223. package/dist/source/ssr/defaultRenderHandler.d.ts +1 -0
  224. package/dist/source/ssr/defaultRenderHandler.jsx +9 -0
  225. package/dist/source/ssr/defaultRenderHandler.jsx.map +1 -0
  226. package/dist/source/ssr/defaultStreamHandler.d.ts +1 -0
  227. package/dist/source/ssr/defaultStreamHandler.jsx +10 -0
  228. package/dist/source/ssr/defaultStreamHandler.jsx.map +1 -0
  229. package/dist/source/ssr/renderRouterToStream.d.ts +8 -0
  230. package/dist/source/ssr/renderRouterToStream.jsx +17 -0
  231. package/dist/source/ssr/renderRouterToStream.jsx.map +1 -0
  232. package/dist/source/ssr/renderRouterToString.d.ts +7 -0
  233. package/dist/source/ssr/renderRouterToString.jsx +20 -0
  234. package/dist/source/ssr/renderRouterToString.jsx.map +1 -0
  235. package/dist/source/ssr/server.d.ts +6 -0
  236. package/dist/source/ssr/server.js +7 -0
  237. package/dist/source/ssr/server.js.map +1 -0
  238. package/dist/source/useBlocker.jsx +44 -27
  239. package/dist/source/useBlocker.jsx.map +1 -1
  240. package/dist/source/useNavigate.jsx +12 -2
  241. package/dist/source/useNavigate.jsx.map +1 -1
  242. package/package.json +34 -7
  243. package/src/Asset.tsx +76 -7
  244. package/src/ClientOnly.tsx +5 -32
  245. package/src/HeadContent.tsx +17 -0
  246. package/src/Match.tsx +103 -81
  247. package/src/Matches.tsx +28 -19
  248. package/src/ScriptOnce.tsx +1 -13
  249. package/src/Transitioner.tsx +7 -7
  250. package/src/index.tsx +1 -18
  251. package/src/lazyRouteComponent.tsx +6 -26
  252. package/src/link.tsx +29 -21
  253. package/src/not-found.tsx +1 -1
  254. package/src/route.tsx +16 -5
  255. package/src/scroll-restoration.tsx +10 -3
  256. package/src/ssr/RouterClient.tsx +43 -0
  257. package/src/ssr/RouterServer.tsx +60 -0
  258. package/src/ssr/client.ts +1 -0
  259. package/src/ssr/defaultRenderHandler.tsx +12 -0
  260. package/src/ssr/defaultStreamHandler.tsx +13 -0
  261. package/src/ssr/renderRouterToStream.tsx +36 -0
  262. package/src/ssr/renderRouterToString.tsx +31 -0
  263. package/src/ssr/server.ts +6 -0
  264. package/src/useBlocker.tsx +48 -32
  265. package/src/useNavigate.tsx +14 -2
package/src/link.tsx CHANGED
@@ -15,7 +15,7 @@ import { useRouter } from './useRouter'
15
15
 
16
16
  import { useIntersectionObserver } from './utils'
17
17
 
18
- import { useMatches } from './Matches'
18
+ import { useMatch } from './useMatch'
19
19
  import type {
20
20
  AnyRouter,
21
21
  Constrain,
@@ -62,7 +62,6 @@ export function useLinkProps<
62
62
  'startTransition',
63
63
  'resetScroll',
64
64
  'viewTransition',
65
- 'children',
66
65
  'target',
67
66
  'disabled',
68
67
  'style',
@@ -113,6 +112,7 @@ export function useLinkProps<
113
112
  'state',
114
113
  'mask',
115
114
  'reloadDocument',
115
+ 'unsafeRelative',
116
116
  ])
117
117
 
118
118
  // If this link simply reloads the current route,
@@ -133,10 +133,11 @@ export function useLinkProps<
133
133
  select: (s) => s.location.searchStr,
134
134
  })
135
135
 
136
- // when `from` is not supplied, use the leaf route of the current matches as the `from` location
136
+ // when `from` is not supplied, use the route of the current match as the `from` location
137
137
  // so relative routing works as expected
138
- const from = useMatches({
139
- select: (matches) => options.from ?? matches[matches.length - 1]?.fullPath,
138
+ const from = useMatch({
139
+ strict: false,
140
+ select: (match) => options.from ?? match.fullPath,
140
141
  })
141
142
 
142
143
  const _options = () => ({
@@ -250,7 +251,6 @@ export function useLinkProps<
250
251
  },
251
252
  },
252
253
  Solid.splitProps(local, [
253
- 'children',
254
254
  'target',
255
255
  'disabled',
256
256
  'style',
@@ -286,7 +286,7 @@ export function useLinkProps<
286
286
 
287
287
  // All is well? Navigate!
288
288
  // N.B. we don't call `router.commitLocation(next) here because we want to run `validateSearch` before committing
289
- return router.navigate({
289
+ router.navigate({
290
290
  ..._options(),
291
291
  replace: local.replace,
292
292
  resetScroll: local.resetScroll,
@@ -294,7 +294,7 @@ export function useLinkProps<
294
294
  startTransition: local.startTransition,
295
295
  viewTransition: local.viewTransition,
296
296
  ignoreBlocker: local.ignoreBlocker,
297
- } as any)
297
+ })
298
298
  }
299
299
  }
300
300
 
@@ -545,29 +545,37 @@ export interface LinkComponentRoute<
545
545
  export function createLink<const TComp>(
546
546
  Comp: Constrain<TComp, any, (props: CreateLinkProps) => Solid.JSX.Element>,
547
547
  ): LinkComponent<TComp> {
548
- return (props) => <Link {...(props as any)} _asChild={Comp} />
548
+ return (props) => <Link {...props} _asChild={Comp} />
549
549
  }
550
550
 
551
- export const Link: LinkComponent<'a'> = (props: any) => {
552
- const [local, rest] = Solid.splitProps(props, ['_asChild'])
551
+ export const Link: LinkComponent<'a'> = (props) => {
552
+ const [local, rest] = Solid.splitProps(
553
+ props as typeof props & { _asChild: any },
554
+ ['_asChild', 'children'],
555
+ )
553
556
 
554
557
  const [_, linkProps] = Solid.splitProps(
555
558
  useLinkProps(rest as unknown as any),
556
- ['type', 'children'],
559
+ ['type'],
557
560
  )
558
561
 
559
- const children = () =>
560
- typeof rest.children === 'function'
561
- ? rest.children({
562
- get isActive() {
563
- return (linkProps as any)['data-status'] === 'active'
564
- },
565
- })
566
- : rest.children
562
+ const children = Solid.createMemo(() => {
563
+ const ch = local.children
564
+ if (typeof ch === 'function') {
565
+ return ch({
566
+ get isActive() {
567
+ return (linkProps as any)['data-status'] === 'active'
568
+ },
569
+ isTransitioning: false,
570
+ })
571
+ }
572
+
573
+ return ch satisfies Solid.JSX.Element
574
+ })
567
575
 
568
576
  return (
569
577
  <Dynamic component={local._asChild ? local._asChild : 'a'} {...linkProps}>
570
- {children}
578
+ {children()}
571
579
  </Dynamic>
572
580
  )
573
581
  }
package/src/not-found.tsx CHANGED
@@ -24,7 +24,7 @@ export function CatchNotFound(props: {
24
24
  throw error
25
25
  }
26
26
  }}
27
- errorComponent={({ error }: { error: Error }) => {
27
+ errorComponent={({ error }) => {
28
28
  if (isNotFound(error)) {
29
29
  return props.fallback?.(error)
30
30
  } else {
package/src/route.tsx CHANGED
@@ -54,6 +54,14 @@ declare module '@tanstack/router-core' {
54
54
  pendingComponent?: RouteComponent
55
55
  }
56
56
 
57
+ export interface RootRouteOptionsExtensions {
58
+ shellComponent?: ({
59
+ children,
60
+ }: {
61
+ children: Solid.JSX.Element
62
+ }) => Solid.JSX.Element
63
+ }
64
+
57
65
  export interface RouteExtensions<
58
66
  in out TId extends string,
59
67
  in out TFullPath extends string,
@@ -480,17 +488,20 @@ export function createRouteMask<
480
488
 
481
489
  export type SolidNode = Solid.JSX.Element
482
490
 
483
- export type SyncRouteComponent<TProps> = (props: TProps) => Solid.JSX.Element
491
+ export interface DefaultRouteTypes<TProps> {
492
+ component: (props: TProps) => any
493
+ }
494
+ export interface RouteTypes<TProps> extends DefaultRouteTypes<TProps> {}
484
495
 
485
- export type AsyncRouteComponent<TProps> = SyncRouteComponent<TProps> & {
496
+ export type AsyncRouteComponent<TProps> = RouteTypes<TProps>['component'] & {
486
497
  preload?: () => Promise<void>
487
498
  }
488
499
 
489
- export type RouteComponent<TProps = any> = AsyncRouteComponent<TProps>
500
+ export type RouteComponent = AsyncRouteComponent<{}>
490
501
 
491
- export type ErrorRouteComponent = RouteComponent<ErrorComponentProps>
502
+ export type ErrorRouteComponent = AsyncRouteComponent<ErrorComponentProps>
492
503
 
493
- export type NotFoundRouteComponent = SyncRouteComponent<NotFoundRouteProps>
504
+ export type NotFoundRouteComponent = RouteTypes<NotFoundRouteProps>['component']
494
505
 
495
506
  export class NotFoundRoute<
496
507
  TParentRoute extends AnyRootRoute,
@@ -14,16 +14,23 @@ export function ScrollRestoration() {
14
14
  const resolvedKey =
15
15
  userKey !== defaultGetScrollRestorationKey(router.latestLocation)
16
16
  ? userKey
17
- : null
17
+ : undefined
18
18
 
19
19
  if (!router.isScrollRestoring || !router.isServer) {
20
20
  return null
21
21
  }
22
22
 
23
+ const restoreScrollOptions: Parameters<typeof restoreScroll>[0] = {
24
+ storageKey,
25
+ shouldScrollRestoration: true,
26
+ }
27
+ if (resolvedKey) {
28
+ restoreScrollOptions.key = resolvedKey
29
+ }
30
+
23
31
  return (
24
32
  <ScriptOnce
25
- children={`(${restoreScroll.toString()})(${JSON.stringify(storageKey)},${JSON.stringify(resolvedKey)}, undefined, true)`}
26
- log={false}
33
+ children={`(${restoreScroll.toString()})(${JSON.stringify(restoreScrollOptions)})`}
27
34
  />
28
35
  )
29
36
  }
@@ -0,0 +1,43 @@
1
+ import { hydrate } from '@tanstack/router-core/ssr/client'
2
+ import { Await } from '../awaited'
3
+ import { HeadContent } from '../HeadContent'
4
+ import { RouterProvider } from '../RouterProvider'
5
+ import type { AnyRouter } from '@tanstack/router-core'
6
+ import type { JSXElement } from 'solid-js'
7
+
8
+ let hydrationPromise: Promise<void | Array<Array<void>>> | undefined
9
+
10
+ const Dummy = (props: { children?: JSXElement }) => <>{props.children}</>
11
+
12
+ export function RouterClient(props: { router: AnyRouter }) {
13
+ if (!hydrationPromise) {
14
+ if (!props.router.state.matches.length) {
15
+ hydrationPromise = hydrate(props.router)
16
+ } else {
17
+ hydrationPromise = Promise.resolve()
18
+ }
19
+ }
20
+ return (
21
+ <Await
22
+ promise={hydrationPromise}
23
+ children={() => (
24
+ <Dummy>
25
+ <Dummy>
26
+ <RouterProvider
27
+ router={props.router}
28
+ InnerWrap={(props) => (
29
+ <Dummy>
30
+ <Dummy>
31
+ <HeadContent />
32
+ {props.children}
33
+ </Dummy>
34
+ <Dummy />
35
+ </Dummy>
36
+ )}
37
+ />
38
+ </Dummy>
39
+ </Dummy>
40
+ )}
41
+ />
42
+ )
43
+ }
@@ -0,0 +1,60 @@
1
+ import {
2
+ Hydration,
3
+ HydrationScript,
4
+ NoHydration,
5
+ ssr,
6
+ useAssets,
7
+ } from 'solid-js/web'
8
+ import { MetaProvider } from '@solidjs/meta'
9
+ import { Asset } from '../Asset'
10
+ import { useTags } from '../HeadContent'
11
+ import { RouterProvider } from '../RouterProvider'
12
+ import { Scripts } from '../Scripts'
13
+ import type { AnyRouter } from '@tanstack/router-core'
14
+
15
+ export function ServerHeadContent() {
16
+ const tags = useTags()
17
+ useAssets(() => {
18
+ return (
19
+ <MetaProvider>
20
+ {tags().map((tag) => (
21
+ <Asset {...tag} />
22
+ ))}
23
+ </MetaProvider>
24
+ )
25
+ })
26
+ return null
27
+ }
28
+
29
+ const docType = ssr('<!DOCTYPE html>')
30
+
31
+ export function RouterServer<TRouter extends AnyRouter>(props: {
32
+ router: TRouter
33
+ }) {
34
+ return (
35
+ <NoHydration>
36
+ {docType as any}
37
+ <html>
38
+ <head>
39
+ <HydrationScript />
40
+ </head>
41
+ <body>
42
+ <Hydration>
43
+ <RouterProvider
44
+ router={props.router}
45
+ InnerWrap={(props) => (
46
+ <NoHydration>
47
+ <MetaProvider>
48
+ <ServerHeadContent />
49
+ <Hydration>{props.children}</Hydration>
50
+ <Scripts />
51
+ </MetaProvider>
52
+ </NoHydration>
53
+ )}
54
+ />
55
+ </Hydration>
56
+ </body>
57
+ </html>
58
+ </NoHydration>
59
+ )
60
+ }
@@ -0,0 +1 @@
1
+ export { RouterClient } from './RouterClient'
@@ -0,0 +1,12 @@
1
+ import { defineHandlerCallback } from '@tanstack/router-core/ssr/server'
2
+ import { RouterServer } from './RouterServer'
3
+ import { renderRouterToString } from './renderRouterToString'
4
+
5
+ export const defaultRenderHandler = defineHandlerCallback(
6
+ ({ router, responseHeaders }) =>
7
+ renderRouterToString({
8
+ router,
9
+ responseHeaders,
10
+ children: () => <RouterServer router={router} />,
11
+ }),
12
+ )
@@ -0,0 +1,13 @@
1
+ import { defineHandlerCallback } from '@tanstack/router-core/ssr/server'
2
+ import { RouterServer } from './RouterServer'
3
+ import { renderRouterToStream } from './renderRouterToStream'
4
+
5
+ export const defaultStreamHandler = defineHandlerCallback(
6
+ ({ request, router, responseHeaders }) =>
7
+ renderRouterToStream({
8
+ request,
9
+ router,
10
+ responseHeaders,
11
+ children: () => <RouterServer router={router} />,
12
+ }),
13
+ )
@@ -0,0 +1,36 @@
1
+ import * as Solid from 'solid-js/web'
2
+ import { isbot } from 'isbot'
3
+ import { transformReadableStreamWithRouter } from '@tanstack/router-core/ssr/server'
4
+ import type { JSXElement } from 'solid-js'
5
+ import type { ReadableStream } from 'node:stream/web'
6
+ import type { AnyRouter } from '@tanstack/router-core'
7
+
8
+ export const renderRouterToStream = async ({
9
+ request,
10
+ router,
11
+ responseHeaders,
12
+ children,
13
+ }: {
14
+ request: Request
15
+ router: AnyRouter
16
+ responseHeaders: Headers
17
+ children: () => JSXElement
18
+ }) => {
19
+ const { writable, readable } = new TransformStream()
20
+
21
+ const stream = Solid.renderToStream(children)
22
+
23
+ if (isbot(request.headers.get('User-Agent'))) {
24
+ await stream
25
+ }
26
+ stream.pipeTo(writable)
27
+
28
+ const responseStream = transformReadableStreamWithRouter(
29
+ router,
30
+ readable as unknown as ReadableStream,
31
+ )
32
+ return new Response(responseStream as any, {
33
+ status: router.state.statusCode,
34
+ headers: responseHeaders,
35
+ })
36
+ }
@@ -0,0 +1,31 @@
1
+ import * as Solid from 'solid-js/web'
2
+ import type { JSXElement } from 'solid-js'
3
+ import type { AnyRouter } from '@tanstack/router-core'
4
+
5
+ export const renderRouterToString = async ({
6
+ router,
7
+ responseHeaders,
8
+ children,
9
+ }: {
10
+ router: AnyRouter
11
+ responseHeaders: Headers
12
+ children: () => JSXElement
13
+ }) => {
14
+ try {
15
+ let html = Solid.renderToString(children)
16
+ const injectedHtml = await Promise.all(router.serverSsr!.injectedHtml).then(
17
+ (htmls) => htmls.join(''),
18
+ )
19
+ html = html.replace(`</body>`, `${injectedHtml}</body>`)
20
+ return new Response(html, {
21
+ status: router.state.statusCode,
22
+ headers: responseHeaders,
23
+ })
24
+ } catch (error) {
25
+ console.error('Render to string error:', error)
26
+ return new Response('Internal Server Error', {
27
+ status: 500,
28
+ headers: responseHeaders,
29
+ })
30
+ }
31
+ }
@@ -0,0 +1,6 @@
1
+ export { RouterServer } from './RouterServer'
2
+ export { defaultRenderHandler } from './defaultRenderHandler'
3
+ export { defaultStreamHandler } from './defaultStreamHandler'
4
+ export { renderRouterToStream } from './renderRouterToStream'
5
+ export { renderRouterToString } from './renderRouterToString'
6
+ export * from '@tanstack/router-core/ssr/server'
@@ -112,20 +112,25 @@ function _resolveBlockerOpts(
112
112
  }
113
113
  }
114
114
 
115
- const shouldBlock = Boolean(opts.condition ?? true)
116
- const fn = opts.blockerFn
115
+ const shouldBlock = Solid.createMemo(() => Boolean(opts.condition ?? true))
117
116
 
118
117
  const _customBlockerFn = async () => {
119
- if (shouldBlock && fn !== undefined) {
120
- return await fn()
118
+ if (shouldBlock() && opts.blockerFn !== undefined) {
119
+ return await opts.blockerFn()
121
120
  }
122
- return shouldBlock
121
+ return shouldBlock()
123
122
  }
124
123
 
125
124
  return {
126
- shouldBlockFn: _customBlockerFn,
127
- enableBeforeUnload: shouldBlock,
128
- withResolver: fn === undefined,
125
+ get shouldBlockFn() {
126
+ return _customBlockerFn
127
+ },
128
+ get enableBeforeUnload() {
129
+ return shouldBlock()
130
+ },
131
+ get withResolver() {
132
+ return opts.blockerFn === undefined
133
+ },
129
134
  }
130
135
  }
131
136
 
@@ -155,15 +160,16 @@ export function useBlocker(
155
160
  opts?: UseBlockerOpts | LegacyBlockerOpts | LegacyBlockerFn,
156
161
  condition?: boolean | any,
157
162
  ): Solid.Accessor<BlockerResolver> | void {
158
- const {
159
- shouldBlockFn,
160
- enableBeforeUnload = true,
161
- disabled = false,
162
- withResolver = false,
163
- } = _resolveBlockerOpts(opts, condition)
163
+ const props = Solid.mergeProps(
164
+ {
165
+ enableBeforeUnload: true,
166
+ disabled: false,
167
+ withResolver: false,
168
+ },
169
+ _resolveBlockerOpts(opts, condition),
170
+ )
164
171
 
165
172
  const router = useRouter()
166
- const { history } = router
167
173
 
168
174
  const [resolver, setResolver] = Solid.createSignal<BlockerResolver>({
169
175
  status: 'idle',
@@ -199,12 +205,12 @@ export function useBlocker(
199
205
  const current = getLocation(blockerFnArgs.currentLocation)
200
206
  const next = getLocation(blockerFnArgs.nextLocation)
201
207
 
202
- const shouldBlock = await shouldBlockFn({
208
+ const shouldBlock = await props.shouldBlockFn({
203
209
  action: blockerFnArgs.action,
204
210
  current,
205
211
  next,
206
212
  })
207
- if (!withResolver) {
213
+ if (!props.withResolver) {
208
214
  return shouldBlock
209
215
  }
210
216
 
@@ -236,9 +242,14 @@ export function useBlocker(
236
242
  return canNavigateAsync
237
243
  }
238
244
 
239
- return disabled
245
+ const disposeBlock = props.disabled
240
246
  ? undefined
241
- : history.block({ blockerFn: blockerFnComposed, enableBeforeUnload })
247
+ : router.history.block({
248
+ blockerFn: blockerFnComposed,
249
+ enableBeforeUnload: props.enableBeforeUnload,
250
+ })
251
+
252
+ Solid.onCleanup(() => disposeBlock?.())
242
253
  })
243
254
 
244
255
  return resolver
@@ -248,23 +259,26 @@ const _resolvePromptBlockerArgs = (
248
259
  props: PromptProps | LegacyPromptProps,
249
260
  ): UseBlockerOpts => {
250
261
  if ('shouldBlockFn' in props) {
251
- return { ...props }
262
+ return props
252
263
  }
253
264
 
254
- const shouldBlock = Boolean(props.condition ?? true)
255
- const fn = props.blockerFn
265
+ const shouldBlock = Solid.createMemo(() => Boolean(props.condition ?? true))
256
266
 
257
267
  const _customBlockerFn = async () => {
258
- if (shouldBlock && fn !== undefined) {
259
- return await fn()
268
+ if (shouldBlock() && props.blockerFn !== undefined) {
269
+ return await props.blockerFn()
260
270
  }
261
271
  return shouldBlock
262
272
  }
263
273
 
264
274
  return {
265
275
  shouldBlockFn: _customBlockerFn,
266
- enableBeforeUnload: shouldBlock,
267
- withResolver: fn === undefined,
276
+ get enableBeforeUnload() {
277
+ return shouldBlock()
278
+ },
279
+ get withResolver() {
280
+ return props.blockerFn === undefined
281
+ },
268
282
  }
269
283
  }
270
284
 
@@ -279,15 +293,17 @@ export function Block<
279
293
  export function Block(opts: LegacyPromptProps): SolidNode
280
294
 
281
295
  export function Block(opts: PromptProps | LegacyPromptProps): SolidNode {
282
- const { children, ...rest } = opts
296
+ const [propsWithChildren, rest] = Solid.splitProps(opts, ['children'])
283
297
  const args = _resolvePromptBlockerArgs(rest)
284
298
 
285
299
  const resolver = useBlocker(args)
286
- return children
287
- ? typeof children === 'function'
288
- ? children(resolver as any)
289
- : children
290
- : null
300
+ const children = Solid.createMemo(() => {
301
+ const child = propsWithChildren.children
302
+ if (resolver && typeof child === 'function') return child(resolver())
303
+ return child
304
+ })
305
+
306
+ return <>{children()}</>
291
307
  }
292
308
 
293
309
  type LegacyPromptProps = {
@@ -1,5 +1,6 @@
1
1
  import * as Solid from 'solid-js'
2
2
  import { useRouter } from './useRouter'
3
+ import { useMatch } from './useMatch'
3
4
  import type {
4
5
  AnyRouter,
5
6
  FromPathOption,
@@ -14,10 +15,21 @@ export function useNavigate<
14
15
  >(_defaultOpts?: {
15
16
  from?: FromPathOption<TRouter, TDefaultFrom>
16
17
  }): UseNavigateResult<TDefaultFrom> {
17
- const { navigate } = useRouter()
18
+ const { navigate, state } = useRouter()
19
+
20
+ const matchIndex = useMatch({
21
+ strict: false,
22
+ select: (match) => match.index,
23
+ })
18
24
 
19
25
  return ((options: NavigateOptions) => {
20
- return navigate({ from: _defaultOpts?.from as any, ...options })
26
+ return navigate({
27
+ ...options,
28
+ from:
29
+ options.from ??
30
+ _defaultOpts?.from ??
31
+ state.matches[matchIndex()]!.fullPath,
32
+ })
21
33
  }) as UseNavigateResult<TDefaultFrom>
22
34
  }
23
35