@tanstack/solid-router 1.108.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 (271) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +29 -0
  3. package/dist/cjs/Asset.cjs +59 -0
  4. package/dist/cjs/Asset.cjs.map +1 -0
  5. package/dist/cjs/Asset.d.cts +2 -0
  6. package/dist/cjs/CatchBoundary.cjs +92 -0
  7. package/dist/cjs/CatchBoundary.cjs.map +1 -0
  8. package/dist/cjs/CatchBoundary.d.cts +11 -0
  9. package/dist/cjs/HeadContent.cjs +129 -0
  10. package/dist/cjs/HeadContent.cjs.map +1 -0
  11. package/dist/cjs/HeadContent.d.cts +8 -0
  12. package/dist/cjs/Match.cjs +340 -0
  13. package/dist/cjs/Match.cjs.map +1 -0
  14. package/dist/cjs/Match.d.cts +8 -0
  15. package/dist/cjs/Matches.cjs +151 -0
  16. package/dist/cjs/Matches.cjs.map +1 -0
  17. package/dist/cjs/Matches.d.cts +69 -0
  18. package/dist/cjs/RouterProvider.cjs +45 -0
  19. package/dist/cjs/RouterProvider.cjs.map +1 -0
  20. package/dist/cjs/RouterProvider.d.cts +35 -0
  21. package/dist/cjs/SafeFragment.cjs +8 -0
  22. package/dist/cjs/SafeFragment.cjs.map +1 -0
  23. package/dist/cjs/SafeFragment.d.cts +1 -0
  24. package/dist/cjs/ScriptOnce.cjs +23 -0
  25. package/dist/cjs/ScriptOnce.cjs.map +1 -0
  26. package/dist/cjs/ScriptOnce.d.cts +5 -0
  27. package/dist/cjs/Scripts.cjs +48 -0
  28. package/dist/cjs/Scripts.cjs.map +1 -0
  29. package/dist/cjs/Scripts.d.cts +1 -0
  30. package/dist/cjs/ScrollRestoration.cjs +37 -0
  31. package/dist/cjs/ScrollRestoration.cjs.map +1 -0
  32. package/dist/cjs/ScrollRestoration.d.cts +15 -0
  33. package/dist/cjs/Transitioner.cjs +132 -0
  34. package/dist/cjs/Transitioner.cjs.map +1 -0
  35. package/dist/cjs/Transitioner.d.cts +1 -0
  36. package/dist/cjs/awaited.cjs +53 -0
  37. package/dist/cjs/awaited.cjs.map +1 -0
  38. package/dist/cjs/awaited.d.cts +11 -0
  39. package/dist/cjs/fileRoute.cjs +90 -0
  40. package/dist/cjs/fileRoute.cjs.map +1 -0
  41. package/dist/cjs/fileRoute.d.cts +58 -0
  42. package/dist/cjs/history.d.cts +8 -0
  43. package/dist/cjs/index.cjs +260 -0
  44. package/dist/cjs/index.cjs.map +1 -0
  45. package/dist/cjs/index.d.cts +53 -0
  46. package/dist/cjs/lazyRouteComponent.cjs +74 -0
  47. package/dist/cjs/lazyRouteComponent.cjs.map +1 -0
  48. package/dist/cjs/lazyRouteComponent.d.cts +7 -0
  49. package/dist/cjs/link.cjs +279 -0
  50. package/dist/cjs/link.cjs.map +1 -0
  51. package/dist/cjs/link.d.cts +113 -0
  52. package/dist/cjs/matchContext.cjs +25 -0
  53. package/dist/cjs/matchContext.cjs.map +1 -0
  54. package/dist/cjs/matchContext.d.cts +3 -0
  55. package/dist/cjs/not-found.cjs +51 -0
  56. package/dist/cjs/not-found.cjs.map +1 -0
  57. package/dist/cjs/not-found.d.cts +27 -0
  58. package/dist/cjs/redirects.cjs +29 -0
  59. package/dist/cjs/redirects.cjs.map +1 -0
  60. package/dist/cjs/redirects.d.cts +21 -0
  61. package/dist/cjs/renderRouteNotFound.cjs +23 -0
  62. package/dist/cjs/renderRouteNotFound.cjs.map +1 -0
  63. package/dist/cjs/renderRouteNotFound.d.cts +3 -0
  64. package/dist/cjs/route.cjs +233 -0
  65. package/dist/cjs/route.cjs.map +1 -0
  66. package/dist/cjs/route.d.cts +297 -0
  67. package/dist/cjs/routeInfo.d.cts +53 -0
  68. package/dist/cjs/router.cjs +1687 -0
  69. package/dist/cjs/router.cjs.map +1 -0
  70. package/dist/cjs/router.d.cts +555 -0
  71. package/dist/cjs/routerContext.cjs +33 -0
  72. package/dist/cjs/routerContext.cjs.map +1 -0
  73. package/dist/cjs/routerContext.d.cts +8 -0
  74. package/dist/cjs/scroll-restoration.cjs +183 -0
  75. package/dist/cjs/scroll-restoration.cjs.map +1 -0
  76. package/dist/cjs/scroll-restoration.d.cts +29 -0
  77. package/dist/cjs/typePrimitives.d.cts +66 -0
  78. package/dist/cjs/useBlocker.cjs +165 -0
  79. package/dist/cjs/useBlocker.cjs.map +1 -0
  80. package/dist/cjs/useBlocker.d.cts +68 -0
  81. package/dist/cjs/useCanGoBack.cjs +8 -0
  82. package/dist/cjs/useCanGoBack.cjs.map +1 -0
  83. package/dist/cjs/useCanGoBack.d.cts +1 -0
  84. package/dist/cjs/useLoaderData.cjs +14 -0
  85. package/dist/cjs/useLoaderData.cjs.map +1 -0
  86. package/dist/cjs/useLoaderData.d.cts +13 -0
  87. package/dist/cjs/useLoaderDeps.cjs +17 -0
  88. package/dist/cjs/useLoaderDeps.cjs.map +1 -0
  89. package/dist/cjs/useLoaderDeps.d.cts +12 -0
  90. package/dist/cjs/useLocation.cjs +10 -0
  91. package/dist/cjs/useLocation.cjs.map +1 -0
  92. package/dist/cjs/useLocation.d.cts +7 -0
  93. package/dist/cjs/useMatch.cjs +39 -0
  94. package/dist/cjs/useMatch.cjs.map +1 -0
  95. package/dist/cjs/useMatch.d.cts +14 -0
  96. package/dist/cjs/useNavigate.cjs +45 -0
  97. package/dist/cjs/useNavigate.cjs.map +1 -0
  98. package/dist/cjs/useNavigate.d.cts +7 -0
  99. package/dist/cjs/useParams.cjs +15 -0
  100. package/dist/cjs/useParams.cjs.map +1 -0
  101. package/dist/cjs/useParams.d.cts +15 -0
  102. package/dist/cjs/useRouteContext.cjs +11 -0
  103. package/dist/cjs/useRouteContext.cjs.map +1 -0
  104. package/dist/cjs/useRouteContext.d.cts +13 -0
  105. package/dist/cjs/useRouter.cjs +29 -0
  106. package/dist/cjs/useRouter.cjs.map +1 -0
  107. package/dist/cjs/useRouter.d.cts +4 -0
  108. package/dist/cjs/useRouterState.cjs +16 -0
  109. package/dist/cjs/useRouterState.cjs.map +1 -0
  110. package/dist/cjs/useRouterState.d.cts +8 -0
  111. package/dist/cjs/useSearch.cjs +15 -0
  112. package/dist/cjs/useSearch.cjs.map +1 -0
  113. package/dist/cjs/useSearch.d.cts +15 -0
  114. package/dist/cjs/utils.cjs +58 -0
  115. package/dist/cjs/utils.cjs.map +1 -0
  116. package/dist/cjs/utils.d.cts +44 -0
  117. package/dist/esm/Asset.d.ts +2 -0
  118. package/dist/esm/Asset.js +59 -0
  119. package/dist/esm/Asset.js.map +1 -0
  120. package/dist/esm/CatchBoundary.d.ts +11 -0
  121. package/dist/esm/CatchBoundary.js +75 -0
  122. package/dist/esm/CatchBoundary.js.map +1 -0
  123. package/dist/esm/HeadContent.d.ts +8 -0
  124. package/dist/esm/HeadContent.js +112 -0
  125. package/dist/esm/HeadContent.js.map +1 -0
  126. package/dist/esm/Match.d.ts +8 -0
  127. package/dist/esm/Match.js +323 -0
  128. package/dist/esm/Match.js.map +1 -0
  129. package/dist/esm/Matches.d.ts +69 -0
  130. package/dist/esm/Matches.js +134 -0
  131. package/dist/esm/Matches.js.map +1 -0
  132. package/dist/esm/RouterProvider.d.ts +35 -0
  133. package/dist/esm/RouterProvider.js +45 -0
  134. package/dist/esm/RouterProvider.js.map +1 -0
  135. package/dist/esm/SafeFragment.d.ts +1 -0
  136. package/dist/esm/SafeFragment.js +8 -0
  137. package/dist/esm/SafeFragment.js.map +1 -0
  138. package/dist/esm/ScriptOnce.d.ts +5 -0
  139. package/dist/esm/ScriptOnce.js +23 -0
  140. package/dist/esm/ScriptOnce.js.map +1 -0
  141. package/dist/esm/Scripts.d.ts +1 -0
  142. package/dist/esm/Scripts.js +48 -0
  143. package/dist/esm/Scripts.js.map +1 -0
  144. package/dist/esm/ScrollRestoration.d.ts +15 -0
  145. package/dist/esm/ScrollRestoration.js +37 -0
  146. package/dist/esm/ScrollRestoration.js.map +1 -0
  147. package/dist/esm/Transitioner.d.ts +1 -0
  148. package/dist/esm/Transitioner.js +115 -0
  149. package/dist/esm/Transitioner.js.map +1 -0
  150. package/dist/esm/awaited.d.ts +11 -0
  151. package/dist/esm/awaited.js +36 -0
  152. package/dist/esm/awaited.js.map +1 -0
  153. package/dist/esm/fileRoute.d.ts +58 -0
  154. package/dist/esm/fileRoute.js +90 -0
  155. package/dist/esm/fileRoute.js.map +1 -0
  156. package/dist/esm/history.d.ts +8 -0
  157. package/dist/esm/index.d.ts +53 -0
  158. package/dist/esm/index.js +149 -0
  159. package/dist/esm/index.js.map +1 -0
  160. package/dist/esm/lazyRouteComponent.d.ts +7 -0
  161. package/dist/esm/lazyRouteComponent.js +74 -0
  162. package/dist/esm/lazyRouteComponent.js.map +1 -0
  163. package/dist/esm/link.d.ts +113 -0
  164. package/dist/esm/link.js +262 -0
  165. package/dist/esm/link.js.map +1 -0
  166. package/dist/esm/matchContext.d.ts +3 -0
  167. package/dist/esm/matchContext.js +8 -0
  168. package/dist/esm/matchContext.js.map +1 -0
  169. package/dist/esm/not-found.d.ts +27 -0
  170. package/dist/esm/not-found.js +51 -0
  171. package/dist/esm/not-found.js.map +1 -0
  172. package/dist/esm/redirects.d.ts +21 -0
  173. package/dist/esm/redirects.js +29 -0
  174. package/dist/esm/redirects.js.map +1 -0
  175. package/dist/esm/renderRouteNotFound.d.ts +3 -0
  176. package/dist/esm/renderRouteNotFound.js +23 -0
  177. package/dist/esm/renderRouteNotFound.js.map +1 -0
  178. package/dist/esm/route.d.ts +297 -0
  179. package/dist/esm/route.js +233 -0
  180. package/dist/esm/route.js.map +1 -0
  181. package/dist/esm/routeInfo.d.ts +53 -0
  182. package/dist/esm/router.d.ts +555 -0
  183. package/dist/esm/router.js +1687 -0
  184. package/dist/esm/router.js.map +1 -0
  185. package/dist/esm/routerContext.d.ts +8 -0
  186. package/dist/esm/routerContext.js +16 -0
  187. package/dist/esm/routerContext.js.map +1 -0
  188. package/dist/esm/scroll-restoration.d.ts +29 -0
  189. package/dist/esm/scroll-restoration.js +183 -0
  190. package/dist/esm/scroll-restoration.js.map +1 -0
  191. package/dist/esm/typePrimitives.d.ts +66 -0
  192. package/dist/esm/useBlocker.d.ts +68 -0
  193. package/dist/esm/useBlocker.js +148 -0
  194. package/dist/esm/useBlocker.js.map +1 -0
  195. package/dist/esm/useCanGoBack.d.ts +1 -0
  196. package/dist/esm/useCanGoBack.js +8 -0
  197. package/dist/esm/useCanGoBack.js.map +1 -0
  198. package/dist/esm/useLoaderData.d.ts +13 -0
  199. package/dist/esm/useLoaderData.js +14 -0
  200. package/dist/esm/useLoaderData.js.map +1 -0
  201. package/dist/esm/useLoaderDeps.d.ts +12 -0
  202. package/dist/esm/useLoaderDeps.js +17 -0
  203. package/dist/esm/useLoaderDeps.js.map +1 -0
  204. package/dist/esm/useLocation.d.ts +7 -0
  205. package/dist/esm/useLocation.js +10 -0
  206. package/dist/esm/useLocation.js.map +1 -0
  207. package/dist/esm/useMatch.d.ts +14 -0
  208. package/dist/esm/useMatch.js +22 -0
  209. package/dist/esm/useMatch.js.map +1 -0
  210. package/dist/esm/useNavigate.d.ts +7 -0
  211. package/dist/esm/useNavigate.js +28 -0
  212. package/dist/esm/useNavigate.js.map +1 -0
  213. package/dist/esm/useParams.d.ts +15 -0
  214. package/dist/esm/useParams.js +15 -0
  215. package/dist/esm/useParams.js.map +1 -0
  216. package/dist/esm/useRouteContext.d.ts +13 -0
  217. package/dist/esm/useRouteContext.js +11 -0
  218. package/dist/esm/useRouteContext.js.map +1 -0
  219. package/dist/esm/useRouter.d.ts +4 -0
  220. package/dist/esm/useRouter.js +12 -0
  221. package/dist/esm/useRouter.js.map +1 -0
  222. package/dist/esm/useRouterState.d.ts +8 -0
  223. package/dist/esm/useRouterState.js +16 -0
  224. package/dist/esm/useRouterState.js.map +1 -0
  225. package/dist/esm/useSearch.d.ts +15 -0
  226. package/dist/esm/useSearch.js +15 -0
  227. package/dist/esm/useSearch.js.map +1 -0
  228. package/dist/esm/utils.d.ts +44 -0
  229. package/dist/esm/utils.js +41 -0
  230. package/dist/esm/utils.js.map +1 -0
  231. package/package.json +75 -0
  232. package/src/Asset.tsx +23 -0
  233. package/src/CatchBoundary.tsx +78 -0
  234. package/src/HeadContent.tsx +146 -0
  235. package/src/Match.tsx +356 -0
  236. package/src/Matches.tsx +348 -0
  237. package/src/RouterProvider.tsx +130 -0
  238. package/src/SafeFragment.tsx +3 -0
  239. package/src/ScriptOnce.tsx +30 -0
  240. package/src/Scripts.tsx +65 -0
  241. package/src/ScrollRestoration.tsx +65 -0
  242. package/src/Transitioner.tsx +152 -0
  243. package/src/awaited.tsx +49 -0
  244. package/src/fileRoute.ts +274 -0
  245. package/src/history.ts +9 -0
  246. package/src/index.tsx +359 -0
  247. package/src/lazyRouteComponent.tsx +114 -0
  248. package/src/link.tsx +1002 -0
  249. package/src/matchContext.tsx +10 -0
  250. package/src/not-found.tsx +69 -0
  251. package/src/redirects.ts +71 -0
  252. package/src/renderRouteNotFound.tsx +27 -0
  253. package/src/route.ts +1477 -0
  254. package/src/routeInfo.ts +239 -0
  255. package/src/router.ts +3066 -0
  256. package/src/routerContext.tsx +26 -0
  257. package/src/scroll-restoration.tsx +337 -0
  258. package/src/typePrimitives.ts +195 -0
  259. package/src/useBlocker.tsx +298 -0
  260. package/src/useCanGoBack.ts +5 -0
  261. package/src/useLoaderData.tsx +64 -0
  262. package/src/useLoaderDeps.tsx +52 -0
  263. package/src/useLocation.tsx +26 -0
  264. package/src/useMatch.tsx +96 -0
  265. package/src/useNavigate.tsx +61 -0
  266. package/src/useParams.tsx +83 -0
  267. package/src/useRouteContext.ts +62 -0
  268. package/src/useRouter.tsx +15 -0
  269. package/src/useRouterState.tsx +32 -0
  270. package/src/useSearch.tsx +84 -0
  271. package/src/utils.ts +96 -0
package/src/link.tsx ADDED
@@ -0,0 +1,1002 @@
1
+ import * as Solid from 'solid-js'
2
+
3
+ import { mergeRefs } from '@solid-primitives/refs'
4
+
5
+ import {
6
+ deepEqual,
7
+ exactPathTest,
8
+ functionalUpdate,
9
+ preloadWarning,
10
+ removeTrailingSlash,
11
+ } from '@tanstack/router-core'
12
+ import { Dynamic } from 'solid-js/web'
13
+ import { useRouterState } from './useRouterState'
14
+ import { useRouter } from './useRouter'
15
+
16
+ import { useIntersectionObserver } from './utils'
17
+
18
+ import { useMatch } from './useMatch'
19
+ import type {
20
+ Constrain,
21
+ ConstrainLiteral,
22
+ Expand,
23
+ IsRequiredParams,
24
+ LinkOptionsProps,
25
+ MakeDifferenceOptional,
26
+ NoInfer,
27
+ NonNullableUpdater,
28
+ ParsedLocation,
29
+ PickRequired,
30
+ RemoveTrailingSlashes,
31
+ ResolveRelativePath,
32
+ Updater,
33
+ ViewTransitionOptions,
34
+ WithoutEmpty,
35
+ } from '@tanstack/router-core'
36
+ import type { HistoryState, ParsedHistoryState } from '@tanstack/history'
37
+ import type {
38
+ AllParams,
39
+ CatchAllPaths,
40
+ CurrentPath,
41
+ FullSearchSchema,
42
+ FullSearchSchemaInput,
43
+ ParentPath,
44
+ RouteByPath,
45
+ RouteByToPath,
46
+ RoutePaths,
47
+ RouteToPath,
48
+ ToPath,
49
+ } from './routeInfo'
50
+ import type { AnyRouter, RegisteredRouter } from './router'
51
+ import type {
52
+ ValidateLinkOptions,
53
+ ValidateLinkOptionsArray,
54
+ } from './typePrimitives'
55
+
56
+ export type FindDescendantToPaths<
57
+ TRouter extends AnyRouter,
58
+ TPrefix extends string,
59
+ > = `${TPrefix}/${string}` & RouteToPath<TRouter>
60
+
61
+ export type InferDescendantToPaths<
62
+ TRouter extends AnyRouter,
63
+ TPrefix extends string,
64
+ TPaths = FindDescendantToPaths<TRouter, TPrefix>,
65
+ > = TPaths extends `${TPrefix}/`
66
+ ? never
67
+ : TPaths extends `${TPrefix}/${infer TRest}`
68
+ ? TRest
69
+ : never
70
+
71
+ export type RelativeToPath<
72
+ TRouter extends AnyRouter,
73
+ TTo extends string,
74
+ TResolvedPath extends string,
75
+ > =
76
+ | (TResolvedPath & RouteToPath<TRouter> extends never
77
+ ? never
78
+ : ToPath<TRouter, TTo>)
79
+ | `${RemoveTrailingSlashes<TTo>}/${InferDescendantToPaths<TRouter, RemoveTrailingSlashes<TResolvedPath>>}`
80
+
81
+ export type RelativeToParentPath<
82
+ TRouter extends AnyRouter,
83
+ TFrom extends string,
84
+ TTo extends string,
85
+ TResolvedPath extends string = ResolveRelativePath<TFrom, TTo>,
86
+ > =
87
+ | RelativeToPath<TRouter, TTo, TResolvedPath>
88
+ | (TTo extends `${string}..` | `${string}../`
89
+ ? TResolvedPath extends '/' | ''
90
+ ? never
91
+ : FindDescendantToPaths<
92
+ TRouter,
93
+ RemoveTrailingSlashes<TResolvedPath>
94
+ > extends never
95
+ ? never
96
+ : `${RemoveTrailingSlashes<TTo>}/${ParentPath<TRouter>}`
97
+ : never)
98
+
99
+ export type RelativeToCurrentPath<
100
+ TRouter extends AnyRouter,
101
+ TFrom extends string,
102
+ TTo extends string,
103
+ TResolvedPath extends string = ResolveRelativePath<TFrom, TTo>,
104
+ > = RelativeToPath<TRouter, TTo, TResolvedPath> | CurrentPath<TRouter>
105
+
106
+ export type AbsoluteToPath<TRouter extends AnyRouter, TFrom extends string> =
107
+ | (string extends TFrom
108
+ ? CurrentPath<TRouter>
109
+ : TFrom extends `/`
110
+ ? never
111
+ : CurrentPath<TRouter>)
112
+ | (string extends TFrom
113
+ ? ParentPath<TRouter>
114
+ : TFrom extends `/`
115
+ ? never
116
+ : ParentPath<TRouter>)
117
+ | RouteToPath<TRouter>
118
+ | (TFrom extends '/'
119
+ ? never
120
+ : string extends TFrom
121
+ ? never
122
+ : InferDescendantToPaths<TRouter, RemoveTrailingSlashes<TFrom>>)
123
+
124
+ export type RelativeToPathAutoComplete<
125
+ TRouter extends AnyRouter,
126
+ TFrom extends string,
127
+ TTo extends string,
128
+ > = string extends TTo
129
+ ? string
130
+ : string extends TFrom
131
+ ? AbsoluteToPath<TRouter, TFrom>
132
+ : TTo & `..${string}` extends never
133
+ ? TTo & `.${string}` extends never
134
+ ? AbsoluteToPath<TRouter, TFrom>
135
+ : RelativeToCurrentPath<TRouter, TFrom, TTo>
136
+ : RelativeToParentPath<TRouter, TFrom, TTo>
137
+
138
+ export type NavigateOptions<
139
+ TRouter extends AnyRouter = RegisteredRouter,
140
+ TFrom extends string = string,
141
+ TTo extends string | undefined = '.',
142
+ TMaskFrom extends string = TFrom,
143
+ TMaskTo extends string = '.',
144
+ > = ToOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo> & NavigateOptionProps
145
+
146
+ export interface NavigateOptionProps {
147
+ // if set to `true`, the router will scroll the element with an id matching the hash into view with default ScrollIntoViewOptions.
148
+ // if set to `false`, the router will not scroll the element with an id matching the hash into view.
149
+ // if set to `ScrollIntoViewOptions`, the router will scroll the element with an id matching the hash into view with the provided options.
150
+ hashScrollIntoView?: boolean | ScrollIntoViewOptions
151
+ // `replace` is a boolean that determines whether the navigation should replace the current history entry or push a new one.
152
+ replace?: boolean
153
+ resetScroll?: boolean
154
+ /** @deprecated All navigations now use startTransition under the hood */
155
+ startTransition?: boolean
156
+ // if set to `true`, the router will wrap the resulting navigation in a document.startViewTransition() call.
157
+ // if set to `ViewTransitionOptions`, the router will pass the `types` field to document.startViewTransition({update: fn, types: viewTransition.types}) call
158
+ viewTransition?: boolean | ViewTransitionOptions
159
+ ignoreBlocker?: boolean
160
+ reloadDocument?: boolean
161
+ href?: string
162
+ }
163
+
164
+ export type ToOptions<
165
+ TRouter extends AnyRouter = RegisteredRouter,
166
+ TFrom extends string = string,
167
+ TTo extends string | undefined = '.',
168
+ TMaskFrom extends string = TFrom,
169
+ TMaskTo extends string = '.',
170
+ > = ToSubOptions<TRouter, TFrom, TTo> & MaskOptions<TRouter, TMaskFrom, TMaskTo>
171
+
172
+ export interface MaskOptions<
173
+ in out TRouter extends AnyRouter,
174
+ in out TMaskFrom extends string,
175
+ in out TMaskTo extends string,
176
+ > {
177
+ _fromLocation?: ParsedLocation
178
+ mask?: ToMaskOptions<TRouter, TMaskFrom, TMaskTo>
179
+ }
180
+
181
+ export type ToMaskOptions<
182
+ TRouter extends AnyRouter = RegisteredRouter,
183
+ TMaskFrom extends string = string,
184
+ TMaskTo extends string = '.',
185
+ > = ToSubOptions<TRouter, TMaskFrom, TMaskTo> & {
186
+ unmaskOnReload?: boolean
187
+ }
188
+
189
+ export type ToSubOptions<
190
+ TRouter extends AnyRouter = RegisteredRouter,
191
+ TFrom extends string = string,
192
+ TTo extends string | undefined = '.',
193
+ > = ToSubOptionsProps<TRouter, TFrom, TTo> &
194
+ SearchParamOptions<TRouter, TFrom, TTo> &
195
+ PathParamOptions<TRouter, TFrom, TTo>
196
+
197
+ export interface RequiredToOptions<
198
+ in out TRouter extends AnyRouter,
199
+ in out TFrom extends string,
200
+ in out TTo extends string | undefined,
201
+ > {
202
+ to: ToPathOption<TRouter, TFrom, TTo> & {}
203
+ }
204
+
205
+ export interface OptionalToOptions<
206
+ in out TRouter extends AnyRouter,
207
+ in out TFrom extends string,
208
+ in out TTo extends string | undefined,
209
+ > {
210
+ to?: ToPathOption<TRouter, TFrom, TTo> & {}
211
+ }
212
+
213
+ export type MakeToRequired<
214
+ TRouter extends AnyRouter,
215
+ TFrom extends string,
216
+ TTo extends string | undefined,
217
+ > = string extends TFrom
218
+ ? string extends TTo
219
+ ? OptionalToOptions<TRouter, TFrom, TTo>
220
+ : TTo & CatchAllPaths<TRouter> extends never
221
+ ? RequiredToOptions<TRouter, TFrom, TTo>
222
+ : OptionalToOptions<TRouter, TFrom, TTo>
223
+ : OptionalToOptions<TRouter, TFrom, TTo>
224
+
225
+ export type ToSubOptionsProps<
226
+ TRouter extends AnyRouter = RegisteredRouter,
227
+ TFrom extends RoutePaths<TRouter['routeTree']> | string = string,
228
+ TTo extends string | undefined = '.',
229
+ > = MakeToRequired<TRouter, TFrom, TTo> & {
230
+ hash?: true | Updater<string>
231
+ state?: true | NonNullableUpdater<ParsedHistoryState, HistoryState>
232
+ from?: FromPathOption<TRouter, TFrom> & {}
233
+ }
234
+
235
+ export type ParamsReducerFn<
236
+ in out TRouter extends AnyRouter,
237
+ in out TParamVariant extends ParamVariant,
238
+ in out TFrom,
239
+ in out TTo,
240
+ > = (
241
+ current: Expand<ResolveFromParams<TRouter, TParamVariant, TFrom>>,
242
+ ) => Expand<ResolveRelativeToParams<TRouter, TParamVariant, TFrom, TTo>>
243
+
244
+ type ParamsReducer<
245
+ TRouter extends AnyRouter,
246
+ TParamVariant extends ParamVariant,
247
+ TFrom,
248
+ TTo,
249
+ > =
250
+ | Expand<ResolveRelativeToParams<TRouter, TParamVariant, TFrom, TTo>>
251
+ | (ParamsReducerFn<TRouter, TParamVariant, TFrom, TTo> & {})
252
+
253
+ type ParamVariant = 'PATH' | 'SEARCH'
254
+
255
+ export type ResolveRoute<
256
+ TRouter extends AnyRouter,
257
+ TFrom,
258
+ TTo,
259
+ TPath = ResolveRelativePath<TFrom, TTo>,
260
+ > = TPath extends string
261
+ ? TFrom extends TPath
262
+ ? RouteByPath<TRouter['routeTree'], TPath>
263
+ : RouteByToPath<TRouter, TPath>
264
+ : never
265
+
266
+ type ResolveFromParamType<TParamVariant extends ParamVariant> =
267
+ TParamVariant extends 'PATH' ? 'allParams' : 'fullSearchSchema'
268
+
269
+ type ResolveFromAllParams<
270
+ TRouter extends AnyRouter,
271
+ TParamVariant extends ParamVariant,
272
+ > = TParamVariant extends 'PATH'
273
+ ? AllParams<TRouter['routeTree']>
274
+ : FullSearchSchema<TRouter['routeTree']>
275
+
276
+ type ResolveFromParams<
277
+ TRouter extends AnyRouter,
278
+ TParamVariant extends ParamVariant,
279
+ TFrom,
280
+ > = string extends TFrom
281
+ ? ResolveFromAllParams<TRouter, TParamVariant>
282
+ : RouteByPath<
283
+ TRouter['routeTree'],
284
+ TFrom
285
+ >['types'][ResolveFromParamType<TParamVariant>]
286
+
287
+ type ResolveToParamType<TParamVariant extends ParamVariant> =
288
+ TParamVariant extends 'PATH' ? 'allParams' : 'fullSearchSchemaInput'
289
+
290
+ type ResolveAllToParams<
291
+ TRouter extends AnyRouter,
292
+ TParamVariant extends ParamVariant,
293
+ > = TParamVariant extends 'PATH'
294
+ ? AllParams<TRouter['routeTree']>
295
+ : FullSearchSchemaInput<TRouter['routeTree']>
296
+
297
+ export type ResolveToParams<
298
+ TRouter extends AnyRouter,
299
+ TParamVariant extends ParamVariant,
300
+ TFrom,
301
+ TTo,
302
+ > =
303
+ ResolveRelativePath<TFrom, TTo> extends infer TPath
304
+ ? undefined extends TPath
305
+ ? never
306
+ : string extends TPath
307
+ ? ResolveAllToParams<TRouter, TParamVariant>
308
+ : TPath extends CatchAllPaths<TRouter>
309
+ ? ResolveAllToParams<TRouter, TParamVariant>
310
+ : ResolveRoute<
311
+ TRouter,
312
+ TFrom,
313
+ TTo
314
+ >['types'][ResolveToParamType<TParamVariant>]
315
+ : never
316
+
317
+ type ResolveRelativeToParams<
318
+ TRouter extends AnyRouter,
319
+ TParamVariant extends ParamVariant,
320
+ TFrom,
321
+ TTo,
322
+ TToParams = ResolveToParams<TRouter, TParamVariant, TFrom, TTo>,
323
+ > = TParamVariant extends 'SEARCH'
324
+ ? TToParams
325
+ : string extends TFrom
326
+ ? TToParams
327
+ : MakeDifferenceOptional<
328
+ ResolveFromParams<TRouter, TParamVariant, TFrom>,
329
+ TToParams
330
+ >
331
+
332
+ export interface MakeOptionalSearchParams<
333
+ in out TRouter extends AnyRouter,
334
+ in out TFrom,
335
+ in out TTo,
336
+ > {
337
+ search?: true | (ParamsReducer<TRouter, 'SEARCH', TFrom, TTo> & {})
338
+ }
339
+
340
+ export interface MakeOptionalPathParams<
341
+ in out TRouter extends AnyRouter,
342
+ in out TFrom,
343
+ in out TTo,
344
+ > {
345
+ params?: true | (ParamsReducer<TRouter, 'PATH', TFrom, TTo> & {})
346
+ }
347
+
348
+ type MakeRequiredParamsReducer<
349
+ TRouter extends AnyRouter,
350
+ TParamVariant extends ParamVariant,
351
+ TFrom,
352
+ TTo,
353
+ > =
354
+ | (string extends TFrom
355
+ ? never
356
+ : ResolveFromParams<TRouter, TParamVariant, TFrom> extends WithoutEmpty<
357
+ PickRequired<
358
+ ResolveRelativeToParams<TRouter, TParamVariant, TFrom, TTo>
359
+ >
360
+ >
361
+ ? true
362
+ : never)
363
+ | (ParamsReducer<TRouter, TParamVariant, TFrom, TTo> & {})
364
+
365
+ export interface MakeRequiredPathParams<
366
+ in out TRouter extends AnyRouter,
367
+ in out TFrom,
368
+ in out TTo,
369
+ > {
370
+ params: MakeRequiredParamsReducer<TRouter, 'PATH', TFrom, TTo> & {}
371
+ }
372
+
373
+ export interface MakeRequiredSearchParams<
374
+ in out TRouter extends AnyRouter,
375
+ in out TFrom,
376
+ in out TTo,
377
+ > {
378
+ search: MakeRequiredParamsReducer<TRouter, 'SEARCH', TFrom, TTo> & {}
379
+ }
380
+
381
+ export type IsRequired<
382
+ TRouter extends AnyRouter,
383
+ TParamVariant extends ParamVariant,
384
+ TFrom,
385
+ TTo,
386
+ > =
387
+ ResolveRelativePath<TFrom, TTo> extends infer TPath
388
+ ? undefined extends TPath
389
+ ? never
390
+ : TPath extends CatchAllPaths<TRouter>
391
+ ? never
392
+ : IsRequiredParams<
393
+ ResolveRelativeToParams<TRouter, TParamVariant, TFrom, TTo>
394
+ >
395
+ : never
396
+
397
+ export type SearchParamOptions<TRouter extends AnyRouter, TFrom, TTo> =
398
+ IsRequired<TRouter, 'SEARCH', TFrom, TTo> extends never
399
+ ? MakeOptionalSearchParams<TRouter, TFrom, TTo>
400
+ : MakeRequiredSearchParams<TRouter, TFrom, TTo>
401
+
402
+ export type PathParamOptions<TRouter extends AnyRouter, TFrom, TTo> =
403
+ IsRequired<TRouter, 'PATH', TFrom, TTo> extends never
404
+ ? MakeOptionalPathParams<TRouter, TFrom, TTo>
405
+ : MakeRequiredPathParams<TRouter, TFrom, TTo>
406
+
407
+ export type ToPathOption<
408
+ TRouter extends AnyRouter = AnyRouter,
409
+ TFrom extends string = string,
410
+ TTo extends string | undefined = string,
411
+ > = ConstrainLiteral<
412
+ TTo,
413
+ RelativeToPathAutoComplete<
414
+ TRouter,
415
+ NoInfer<TFrom> extends string ? NoInfer<TFrom> : '',
416
+ NoInfer<TTo> & string
417
+ >
418
+ >
419
+
420
+ export type FromPathOption<TRouter extends AnyRouter, TFrom> = ConstrainLiteral<
421
+ TFrom,
422
+ RoutePaths<TRouter['routeTree']>
423
+ >
424
+
425
+ export type LinkOptions<
426
+ TRouter extends AnyRouter = RegisteredRouter,
427
+ TFrom extends string = string,
428
+ TTo extends string | undefined = '.',
429
+ TMaskFrom extends string = TFrom,
430
+ TMaskTo extends string = '.',
431
+ > = NavigateOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo> & LinkOptionsProps
432
+
433
+ // type Test1 = ResolveRelativePath<'/', '/posts'>
434
+ // // ^?
435
+ // type Test4 = ResolveRelativePath<'/posts/1/comments', '../..'>
436
+ // // ^?
437
+ // type Test5 = ResolveRelativePath<'/posts/1/comments', '../../..'>
438
+ // // ^?
439
+ // type Test6 = ResolveRelativePath<'/posts/1/comments', './1'>
440
+ // // ^?
441
+ // type Test7 = ResolveRelativePath<'/posts/1/comments', './1/2'>
442
+ // // ^?
443
+ // type Test8 = ResolveRelativePath<'/posts/1/comments', '../edit'>
444
+ // // ^?
445
+ // type Test9 = ResolveRelativePath<'/posts/1/comments', '1'>
446
+ // // ^?
447
+ // type Test10 = ResolveRelativePath<'/posts/1/comments', './1'>
448
+ // // ^?
449
+ // type Test11 = ResolveRelativePath<'/posts/1/comments', './1/2'>
450
+ // // ^?
451
+ type LinkCurrentTargetElement = {
452
+ preloadTimeout?: null | ReturnType<typeof setTimeout>
453
+ }
454
+
455
+ export function useLinkProps<
456
+ TRouter extends AnyRouter = RegisteredRouter,
457
+ TFrom extends RoutePaths<TRouter['routeTree']> | string = string,
458
+ TTo extends string = '',
459
+ TMaskFrom extends RoutePaths<TRouter['routeTree']> | string = TFrom,
460
+ TMaskTo extends string = '',
461
+ >(
462
+ options: UseLinkPropsOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>,
463
+ ): Solid.ComponentProps<'a'> {
464
+ const router = useRouter()
465
+ const [isTransitioning, setIsTransitioning] = Solid.createSignal(false)
466
+ let hasRenderFetched = false
467
+
468
+ const [local, rest] = Solid.splitProps(
469
+ Solid.mergeProps(
470
+ {
471
+ activeProps: () => ({ class: 'active' }),
472
+ inactiveProps: () => ({}),
473
+ },
474
+ options,
475
+ ),
476
+ [
477
+ 'activeProps',
478
+ 'inactiveProps',
479
+ 'activeOptions',
480
+ 'to',
481
+ 'preload',
482
+ 'preloadDelay',
483
+ 'hashScrollIntoView',
484
+ 'replace',
485
+ 'startTransition',
486
+ 'resetScroll',
487
+ 'viewTransition',
488
+ 'children',
489
+ 'target',
490
+ 'disabled',
491
+ 'style',
492
+ 'class',
493
+ 'onClick',
494
+ 'onFocus',
495
+ 'onMouseEnter',
496
+ 'onMouseLeave',
497
+ 'onMouseOver',
498
+ 'onMouseOut',
499
+ 'onTouchStart',
500
+ 'ignoreBlocker',
501
+ ],
502
+ )
503
+
504
+ // const {
505
+ // // custom props
506
+ // activeProps = () => ({ class: 'active' }),
507
+ // inactiveProps = () => ({}),
508
+ // activeOptions,
509
+ // to,
510
+ // preload: userPreload,
511
+ // preloadDelay: userPreloadDelay,
512
+ // hashScrollIntoView,
513
+ // replace,
514
+ // startTransition,
515
+ // resetScroll,
516
+ // viewTransition,
517
+ // // element props
518
+ // children,
519
+ // target,
520
+ // disabled,
521
+ // style,
522
+ // class,
523
+ // onClick,
524
+ // onFocus,
525
+ // onMouseEnter,
526
+ // onMouseLeave,
527
+ // onTouchStart,
528
+ // ignoreBlocker,
529
+ // ...rest
530
+ // } = options
531
+
532
+ const [_, propsSafeToSpread] = Solid.splitProps(rest, [
533
+ 'params',
534
+ 'search',
535
+ 'hash',
536
+ 'state',
537
+ 'mask',
538
+ 'reloadDocument',
539
+ ])
540
+
541
+ // If this link simply reloads the current route,
542
+ // make sure it has a new key so it will trigger a data refresh
543
+
544
+ // If this `to` is a valid external URL, return
545
+ // null for LinkUtils
546
+
547
+ const type: Solid.Accessor<'internal' | 'external'> = () => {
548
+ try {
549
+ new URL(`${local.to}`)
550
+ return 'external'
551
+ } catch {}
552
+ return 'internal'
553
+ }
554
+
555
+ const currentSearch = useRouterState({
556
+ select: (s) => s.location.searchStr,
557
+ })
558
+
559
+ // In the rare event that the user bypasses type-safety and doesn't supply a `from`
560
+ // we'll use the current route as the `from` location so relative routing works as expected
561
+ const parentRouteId = useMatch({ strict: false, select: (s) => s.pathname })
562
+
563
+ // Use it as the default `from` location
564
+ options = {
565
+ from: parentRouteId(),
566
+ ...options,
567
+ }
568
+
569
+ const next = Solid.createMemo(() => {
570
+ currentSearch()
571
+ return router.buildLocation(options as any)
572
+ })
573
+
574
+ const preload = Solid.createMemo(() => {
575
+ if (options.reloadDocument) {
576
+ return false
577
+ }
578
+ return local.preload ?? router.options.defaultPreload
579
+ })
580
+ const preloadDelay = () =>
581
+ local.preloadDelay ?? router.options.defaultPreloadDelay ?? 0
582
+
583
+ const isActive = useRouterState({
584
+ select: (s) => {
585
+ if (local.activeOptions?.exact) {
586
+ const testExact = exactPathTest(
587
+ s.location.pathname,
588
+ next().pathname,
589
+ router.basepath,
590
+ )
591
+ if (!testExact) {
592
+ return false
593
+ }
594
+ } else {
595
+ const currentPathSplit = removeTrailingSlash(
596
+ s.location.pathname,
597
+ router.basepath,
598
+ ).split('/')
599
+ const nextPathSplit = removeTrailingSlash(
600
+ next()?.pathname,
601
+ router.basepath,
602
+ )?.split('/')
603
+
604
+ const pathIsFuzzyEqual = nextPathSplit?.every(
605
+ (d, i) => d === currentPathSplit[i],
606
+ )
607
+ if (!pathIsFuzzyEqual) {
608
+ return false
609
+ }
610
+ }
611
+
612
+ if (local.activeOptions?.includeSearch ?? true) {
613
+ const searchTest = deepEqual(s.location.search, next().search, {
614
+ partial: !local.activeOptions?.exact,
615
+ ignoreUndefined: !local.activeOptions?.explicitUndefined,
616
+ })
617
+ if (!searchTest) {
618
+ return false
619
+ }
620
+ }
621
+
622
+ if (local.activeOptions?.includeHash) {
623
+ return s.location.hash === next().hash
624
+ }
625
+ return true
626
+ },
627
+ })
628
+
629
+ const doPreload = () =>
630
+ router.preloadRoute(options as any).catch((err: any) => {
631
+ console.warn(err)
632
+ console.warn(preloadWarning)
633
+ })
634
+
635
+ const preloadViewportIoCallback = (
636
+ entry: IntersectionObserverEntry | undefined,
637
+ ) => {
638
+ if (entry?.isIntersecting) {
639
+ doPreload()
640
+ }
641
+ }
642
+
643
+ const [ref, setRef] = Solid.createSignal<Element | null>(null)
644
+
645
+ useIntersectionObserver(
646
+ ref,
647
+ preloadViewportIoCallback,
648
+ { rootMargin: '100px' },
649
+ { disabled: !!local.disabled || !(preload() === 'viewport') },
650
+ )
651
+
652
+ Solid.createEffect(() => {
653
+ if (hasRenderFetched) {
654
+ return
655
+ }
656
+ if (!local.disabled && preload() === 'render') {
657
+ doPreload()
658
+ hasRenderFetched = true
659
+ }
660
+ })
661
+
662
+ if (type() === 'external') {
663
+ return Solid.mergeProps(
664
+ propsSafeToSpread,
665
+ {
666
+ ref,
667
+ get type() {
668
+ return type()
669
+ },
670
+ get href() {
671
+ return local.to
672
+ },
673
+ },
674
+ Solid.splitProps(local, [
675
+ 'children',
676
+ 'target',
677
+ 'disabled',
678
+ 'style',
679
+ 'class',
680
+ 'onClick',
681
+ 'onFocus',
682
+ 'onMouseEnter',
683
+ 'onMouseLeave',
684
+ 'onMouseOut',
685
+ 'onMouseOver',
686
+ 'onTouchStart',
687
+ ])[0],
688
+ ) as any
689
+ }
690
+
691
+ // The click handler
692
+ const handleClick = (e: MouseEvent) => {
693
+ if (
694
+ !local.disabled &&
695
+ !isCtrlEvent(e) &&
696
+ !e.defaultPrevented &&
697
+ (!local.target || local.target === '_self') &&
698
+ e.button === 0
699
+ ) {
700
+ e.preventDefault()
701
+
702
+ setIsTransitioning(true)
703
+
704
+ const unsub = router.subscribe('onResolved', () => {
705
+ unsub()
706
+ setIsTransitioning(false)
707
+ })
708
+
709
+ // All is well? Navigate!
710
+ // N.B. we don't call `router.commitLocation(next) here because we want to run `validateSearch` before committing
711
+ return router.navigate({
712
+ ...options,
713
+ replace: local.replace,
714
+ resetScroll: local.resetScroll,
715
+ hashScrollIntoView: local.hashScrollIntoView,
716
+ startTransition: local.startTransition,
717
+ viewTransition: local.viewTransition,
718
+ ignoreBlocker: local.ignoreBlocker,
719
+ } as any)
720
+ }
721
+ }
722
+
723
+ // The click handler
724
+ const handleFocus = (_: MouseEvent) => {
725
+ if (local.disabled) return
726
+ if (preload()) {
727
+ doPreload()
728
+ }
729
+ }
730
+
731
+ const handleTouchStart = handleFocus
732
+
733
+ const handleEnter = (e: MouseEvent) => {
734
+ if (local.disabled) return
735
+ const eventTarget = (e.target || {}) as LinkCurrentTargetElement
736
+
737
+ if (preload()) {
738
+ if (eventTarget.preloadTimeout) {
739
+ return
740
+ }
741
+
742
+ eventTarget.preloadTimeout = setTimeout(() => {
743
+ eventTarget.preloadTimeout = null
744
+ doPreload()
745
+ }, preloadDelay())
746
+ }
747
+ }
748
+
749
+ const handleLeave = (e: MouseEvent) => {
750
+ if (local.disabled) return
751
+ const eventTarget = (e.target || {}) as LinkCurrentTargetElement
752
+
753
+ if (eventTarget.preloadTimeout) {
754
+ clearTimeout(eventTarget.preloadTimeout)
755
+ eventTarget.preloadTimeout = null
756
+ }
757
+ }
758
+
759
+ /** Call a JSX.EventHandlerUnion with the event. */
760
+ function callHandler<T, TEvent extends Event>(
761
+ event: TEvent & { currentTarget: T; target: Element },
762
+ handler: Solid.JSX.EventHandlerUnion<T, TEvent> | undefined,
763
+ ) {
764
+ if (handler) {
765
+ if (typeof handler === 'function') {
766
+ handler(event)
767
+ } else {
768
+ handler[0](handler[1], event)
769
+ }
770
+ }
771
+
772
+ return event.defaultPrevented
773
+ }
774
+
775
+ function composeEventHandlers<T>(
776
+ handlers: Array<Solid.JSX.EventHandlerUnion<T, any> | undefined>,
777
+ ) {
778
+ return (event: any) => {
779
+ for (const handler of handlers) {
780
+ callHandler(event, handler)
781
+ }
782
+ }
783
+ }
784
+
785
+ // Get the active props
786
+ const resolvedActiveProps: () => Omit<Solid.ComponentProps<'a'>, 'style'> & {
787
+ style?: Solid.JSX.CSSProperties
788
+ } = () =>
789
+ isActive() ? (functionalUpdate(local.activeProps as any, {}) ?? {}) : {}
790
+
791
+ // Get the inactive props
792
+ const resolvedInactiveProps: () => Omit<
793
+ Solid.ComponentProps<'a'>,
794
+ 'style'
795
+ > & { style?: Solid.JSX.CSSProperties } = () =>
796
+ isActive() ? {} : functionalUpdate(local.inactiveProps, {})
797
+
798
+ const resolvedClassName = () =>
799
+ [local.class, resolvedActiveProps().class, resolvedInactiveProps().class]
800
+ .filter(Boolean)
801
+ .join(' ')
802
+
803
+ const resolvedStyle = () => ({
804
+ ...local.style,
805
+ ...resolvedActiveProps().style,
806
+ ...resolvedInactiveProps().style,
807
+ })
808
+
809
+ const href = Solid.createMemo(() => {
810
+ const nextLocation = next()
811
+ const maskedLocation = nextLocation?.maskedLocation
812
+
813
+ return options.disabled
814
+ ? undefined
815
+ : maskedLocation
816
+ ? router.history.createHref(maskedLocation.href)
817
+ : router.history.createHref(nextLocation?.href)
818
+ })
819
+
820
+ return Solid.mergeProps(
821
+ propsSafeToSpread,
822
+ resolvedActiveProps,
823
+ resolvedInactiveProps,
824
+ () => {
825
+ return {
826
+ href: href(),
827
+ ref: mergeRefs(setRef, options.ref),
828
+ onClick: composeEventHandlers([local.onClick, handleClick]),
829
+ onFocus: composeEventHandlers([local.onFocus, handleFocus]),
830
+ onMouseEnter: composeEventHandlers([local.onMouseEnter, handleEnter]),
831
+ onMouseOver: composeEventHandlers([local.onMouseOver, handleEnter]),
832
+ onMouseLeave: composeEventHandlers([local.onMouseLeave, handleLeave]),
833
+ onMouseOut: composeEventHandlers([local.onMouseOut, handleLeave]),
834
+ onTouchStart: composeEventHandlers([
835
+ local.onTouchStart,
836
+ handleTouchStart,
837
+ ]),
838
+ disabled: !!local.disabled,
839
+ target: local.target,
840
+ ...(Object.keys(resolvedStyle).length && { style: resolvedStyle }),
841
+ ...(resolvedClassName() && { class: resolvedClassName() }),
842
+ ...(local.disabled && {
843
+ role: 'link',
844
+ 'aria-disabled': true,
845
+ }),
846
+ ...(isActive() && { 'data-status': 'active', 'aria-current': 'page' }),
847
+ ...(isTransitioning() && { 'data-transitioning': 'transitioning' }),
848
+ }
849
+ },
850
+ ) as any
851
+ }
852
+
853
+ export type UseLinkPropsOptions<
854
+ TRouter extends AnyRouter = RegisteredRouter,
855
+ TFrom extends RoutePaths<TRouter['routeTree']> | string = string,
856
+ TTo extends string | undefined = '.',
857
+ TMaskFrom extends RoutePaths<TRouter['routeTree']> | string = TFrom,
858
+ TMaskTo extends string = '.',
859
+ > = ActiveLinkOptions<'a', TRouter, TFrom, TTo, TMaskFrom, TMaskTo> &
860
+ Omit<Solid.ComponentProps<'a'>, 'style'> & { style?: Solid.JSX.CSSProperties }
861
+
862
+ export type ActiveLinkOptions<
863
+ TComp = 'a',
864
+ TRouter extends AnyRouter = RegisteredRouter,
865
+ TFrom extends string = string,
866
+ TTo extends string | undefined = '.',
867
+ TMaskFrom extends string = TFrom,
868
+ TMaskTo extends string = '.',
869
+ > = LinkOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo> &
870
+ ActiveLinkOptionProps<TComp>
871
+
872
+ type ActiveLinkProps<TComp> = Partial<
873
+ LinkComponentSolidProps<TComp> & {
874
+ [key: `data-${string}`]: unknown
875
+ }
876
+ >
877
+
878
+ export interface ActiveLinkOptionProps<TComp = 'a'> {
879
+ /**
880
+ * A function that returns additional props for the `active` state of this link.
881
+ * These props override other props passed to the link (`style`'s are merged, `class`'s are concatenated)
882
+ */
883
+ activeProps?: ActiveLinkProps<TComp> | (() => ActiveLinkProps<TComp>)
884
+ /**
885
+ * A function that returns additional props for the `inactive` state of this link.
886
+ * These props override other props passed to the link (`style`'s are merged, `class`'s are concatenated)
887
+ */
888
+ inactiveProps?: ActiveLinkProps<TComp> | (() => ActiveLinkProps<TComp>)
889
+ }
890
+
891
+ export type LinkProps<
892
+ TComp = 'a',
893
+ TRouter extends AnyRouter = RegisteredRouter,
894
+ TFrom extends string = string,
895
+ TTo extends string | undefined = '.',
896
+ TMaskFrom extends string = TFrom,
897
+ TMaskTo extends string = '.',
898
+ > = ActiveLinkOptions<TComp, TRouter, TFrom, TTo, TMaskFrom, TMaskTo> &
899
+ LinkPropsChildren
900
+
901
+ export interface LinkPropsChildren {
902
+ // If a function is passed as a child, it will be given the `isActive` boolean to aid in further styling on the element it returns
903
+ children?:
904
+ | Solid.JSX.Element
905
+ | ((state: {
906
+ isActive: boolean
907
+ isTransitioning: boolean
908
+ }) => Solid.JSX.Element)
909
+ }
910
+
911
+ type LinkComponentSolidProps<TComp> = TComp extends Solid.ValidComponent
912
+ ? Omit<Solid.ComponentProps<TComp>, keyof CreateLinkProps>
913
+ : never
914
+
915
+ export type LinkComponentProps<
916
+ TComp = 'a',
917
+ TRouter extends AnyRouter = RegisteredRouter,
918
+ TFrom extends string = string,
919
+ TTo extends string | undefined = '.',
920
+ TMaskFrom extends string = TFrom,
921
+ TMaskTo extends string = '.',
922
+ > = LinkComponentSolidProps<TComp> &
923
+ LinkProps<TComp, TRouter, TFrom, TTo, TMaskFrom, TMaskTo>
924
+
925
+ export type CreateLinkProps = LinkProps<
926
+ any,
927
+ any,
928
+ string,
929
+ string,
930
+ string,
931
+ string
932
+ >
933
+
934
+ export type LinkComponent<TComp> = <
935
+ TRouter extends AnyRouter = RegisteredRouter,
936
+ const TFrom extends string = string,
937
+ const TTo extends string | undefined = undefined,
938
+ const TMaskFrom extends string = TFrom,
939
+ const TMaskTo extends string = '',
940
+ >(
941
+ props: LinkComponentProps<TComp, TRouter, TFrom, TTo, TMaskFrom, TMaskTo>,
942
+ ) => Solid.JSX.Element
943
+
944
+ export function createLink<const TComp>(
945
+ Comp: Constrain<TComp, any, (props: CreateLinkProps) => Solid.JSX.Element>,
946
+ ): LinkComponent<TComp> {
947
+ return (props) => <Link {...(props as any)} _asChild={Comp} />
948
+ }
949
+
950
+ export const Link: LinkComponent<'a'> = (props: any) => {
951
+ const [local, rest] = Solid.splitProps(props, ['_asChild'])
952
+
953
+ const [_, linkProps] = Solid.splitProps(
954
+ useLinkProps(rest as unknown as any),
955
+ ['type', 'children'],
956
+ )
957
+
958
+ const children = () =>
959
+ typeof rest.children === 'function'
960
+ ? rest.children({
961
+ get isActive() {
962
+ return (linkProps as any)['data-status'] === 'active'
963
+ },
964
+ })
965
+ : rest.children
966
+
967
+ if (typeof local._asChild === 'undefined') {
968
+ // the Retlocal.urnType of useLinkProps returns the correct type for a <a> element, not a general component that has a disabled prop
969
+ // @ts-expect-error
970
+ delete linkProps.disabled
971
+ }
972
+
973
+ return (
974
+ <Dynamic component={local._asChild ? local._asChild : 'a'} {...linkProps}>
975
+ {children}
976
+ </Dynamic>
977
+ )
978
+ }
979
+
980
+ function isCtrlEvent(e: MouseEvent) {
981
+ return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey)
982
+ }
983
+
984
+ export type LinkOptionsFnOptions<
985
+ TOptions,
986
+ TComp,
987
+ TRouter extends AnyRouter = RegisteredRouter,
988
+ > =
989
+ TOptions extends ReadonlyArray<any>
990
+ ? ValidateLinkOptionsArray<TOptions, TComp, TRouter>
991
+ : ValidateLinkOptions<TOptions, TComp, TRouter>
992
+
993
+ export type LinkOptionsFn<TComp> = <
994
+ const TOptions,
995
+ TRouter extends AnyRouter = RegisteredRouter,
996
+ >(
997
+ options: LinkOptionsFnOptions<TOptions, TComp, TRouter>,
998
+ ) => TOptions
999
+
1000
+ export const linkOptions: LinkOptionsFn<'a'> = (options) => {
1001
+ return options as any
1002
+ }