@tanstack/router-core 0.0.1-beta.35 → 0.0.1-beta.39

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 (38) hide show
  1. package/build/cjs/index.js +2 -1
  2. package/build/cjs/index.js.map +1 -1
  3. package/build/cjs/path.js +5 -7
  4. package/build/cjs/path.js.map +1 -1
  5. package/build/cjs/route.js +112 -96
  6. package/build/cjs/route.js.map +1 -1
  7. package/build/cjs/routeConfig.js +2 -2
  8. package/build/cjs/routeConfig.js.map +1 -1
  9. package/build/cjs/routeMatch.js +107 -65
  10. package/build/cjs/routeMatch.js.map +1 -1
  11. package/build/cjs/router.js +352 -372
  12. package/build/cjs/router.js.map +1 -1
  13. package/build/cjs/searchParams.js +4 -3
  14. package/build/cjs/searchParams.js.map +1 -1
  15. package/build/cjs/sharedClone.js +122 -0
  16. package/build/cjs/sharedClone.js.map +1 -0
  17. package/build/cjs/utils.js +1 -59
  18. package/build/cjs/utils.js.map +1 -1
  19. package/build/esm/index.js +686 -614
  20. package/build/esm/index.js.map +1 -1
  21. package/build/stats-html.html +1 -1
  22. package/build/stats-react.json +183 -158
  23. package/build/types/index.d.ts +61 -78
  24. package/build/umd/index.development.js +1032 -617
  25. package/build/umd/index.development.js.map +1 -1
  26. package/build/umd/index.production.js +1 -1
  27. package/build/umd/index.production.js.map +1 -1
  28. package/package.json +2 -1
  29. package/src/index.ts +1 -0
  30. package/src/link.ts +20 -12
  31. package/src/route.ts +160 -140
  32. package/src/routeConfig.ts +7 -2
  33. package/src/routeMatch.ts +146 -99
  34. package/src/router.ts +462 -523
  35. package/src/sharedClone.ts +118 -0
  36. package/src/utils.ts +0 -65
  37. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +0 -31
  38. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js.map +0 -1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tanstack/router-core",
3
3
  "author": "Tanner Linsley",
4
- "version": "0.0.1-beta.35",
4
+ "version": "0.0.1-beta.39",
5
5
  "license": "MIT",
6
6
  "repository": "tanstack/router",
7
7
  "homepage": "https://tanstack.com/router",
@@ -40,6 +40,7 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@babel/runtime": "^7.16.7",
43
+ "@solidjs/reactivity": "^0.0.6",
43
44
  "history": "^5.2.0",
44
45
  "tiny-invariant": "^1.3.1"
45
46
  },
package/src/index.ts CHANGED
@@ -17,3 +17,4 @@ export * from './routeMatch'
17
17
  export * from './router'
18
18
  export * from './searchParams'
19
19
  export * from './utils'
20
+ export * from './sharedClone'
package/src/link.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { AnyPathParams } from './routeConfig'
2
1
  import {
3
2
  AnyAllRouteInfo,
4
3
  DefaultAllRouteInfo,
@@ -112,11 +111,20 @@ export type RelativeToPathAutoComplete<
112
111
  ]
113
112
  ? `${TTo}${Join<RestPath>}`
114
113
  : never
115
- : './' | '../' | AllPaths
114
+ :
115
+ | (TFrom extends `/`
116
+ ? never
117
+ : SplitPaths extends [...Split<TFrom, false>, ...infer RestPath]
118
+ ? Join<RestPath> extends { length: 0 }
119
+ ? never
120
+ : './'
121
+ : never)
122
+ | (TFrom extends `/` ? never : '../')
123
+ | AllPaths
116
124
 
117
- export type NavigateOptionsAbsolute<
125
+ export type NavigateOptions<
118
126
  TAllRouteInfo extends AnyAllRouteInfo = DefaultAllRouteInfo,
119
- TFrom extends ValidFromPath<TAllRouteInfo> = '/',
127
+ TFrom extends TAllRouteInfo['routePaths'] = '/',
120
128
  TTo extends string = '.',
121
129
  > = ToOptions<TAllRouteInfo, TFrom, TTo> & {
122
130
  // Whether to replace the current history stack instead of pushing a new one
@@ -125,7 +133,7 @@ export type NavigateOptionsAbsolute<
125
133
 
126
134
  export type ToOptions<
127
135
  TAllRouteInfo extends AnyAllRouteInfo = DefaultAllRouteInfo,
128
- TFrom extends ValidFromPath<TAllRouteInfo> = '/',
136
+ TFrom extends TAllRouteInfo['routePaths'] = '/',
129
137
  TTo extends string = '.',
130
138
  TResolvedTo = ResolveRelativePath<TFrom, NoInfer<TTo>>,
131
139
  > = {
@@ -142,7 +150,7 @@ export type ToOptions<
142
150
  SearchParamOptions<TAllRouteInfo, TFrom, TResolvedTo> &
143
151
  PathParamOptions<TAllRouteInfo, TFrom, TResolvedTo>
144
152
 
145
- type SearchParamOptions<
153
+ export type SearchParamOptions<
146
154
  TAllRouteInfo extends AnyAllRouteInfo,
147
155
  TFrom,
148
156
  TTo,
@@ -183,7 +191,7 @@ type SearchReducer<TFrom, TTo> =
183
191
  | { [TKey in keyof TTo]: TTo[TKey] }
184
192
  | ((current: TFrom) => TTo)
185
193
 
186
- type PathParamOptions<
194
+ export type PathParamOptions<
187
195
  TAllRouteInfo extends AnyAllRouteInfo,
188
196
  TFrom,
189
197
  TTo,
@@ -219,7 +227,7 @@ type ParamsReducer<TFrom, TTo> = TTo | ((current: TFrom) => TTo)
219
227
 
220
228
  export type ToPathOption<
221
229
  TAllRouteInfo extends AnyAllRouteInfo = DefaultAllRouteInfo,
222
- TFrom extends ValidFromPath<TAllRouteInfo> = '/',
230
+ TFrom extends TAllRouteInfo['routePaths'] = '/',
223
231
  TTo extends string = '.',
224
232
  > =
225
233
  | TTo
@@ -231,7 +239,7 @@ export type ToPathOption<
231
239
 
232
240
  export type ToIdOption<
233
241
  TAllRouteInfo extends AnyAllRouteInfo = DefaultAllRouteInfo,
234
- TFrom extends ValidFromPath<TAllRouteInfo> = '/',
242
+ TFrom extends TAllRouteInfo['routePaths'] = '/',
235
243
  TTo extends string = '.',
236
244
  > =
237
245
  | TTo
@@ -241,16 +249,16 @@ export type ToIdOption<
241
249
  NoInfer<TTo> & string
242
250
  >
243
251
 
244
- interface ActiveOptions {
252
+ export interface ActiveOptions {
245
253
  exact?: boolean
246
254
  includeHash?: boolean
247
255
  }
248
256
 
249
257
  export type LinkOptions<
250
258
  TAllRouteInfo extends AnyAllRouteInfo = DefaultAllRouteInfo,
251
- TFrom extends ValidFromPath<TAllRouteInfo> = '/',
259
+ TFrom extends TAllRouteInfo['routePaths'] = '/',
252
260
  TTo extends string = '.',
253
- > = NavigateOptionsAbsolute<TAllRouteInfo, TFrom, TTo> & {
261
+ > = NavigateOptions<TAllRouteInfo, TFrom, TTo> & {
254
262
  // The standard anchor tag target attribute
255
263
  target?: HTMLAnchorElement['target']
256
264
  // Defaults to `{ exact: false, includeHash: false }`
package/src/route.ts CHANGED
@@ -22,6 +22,7 @@ import {
22
22
  Router,
23
23
  } from './router'
24
24
  import { NoInfer } from './utils'
25
+ import { createStore } from '@solidjs/reactivity'
25
26
 
26
27
  export interface AnyRoute extends Route<any, any, any> {}
27
28
 
@@ -38,31 +39,8 @@ export interface Route<
38
39
  parentRoute?: AnyRoute
39
40
  childRoutes?: AnyRoute[]
40
41
  options: RouteOptions
42
+ originalIndex: number
41
43
  router: Router<TAllRouteInfo['routeConfig'], TAllRouteInfo, TRouterContext>
42
- buildLink: <TTo extends string = '.'>(
43
- options: Omit<
44
- LinkOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo>,
45
- 'from'
46
- >,
47
- ) => LinkInfo
48
- matchRoute: <
49
- TTo extends string = '.',
50
- TResolved extends string = ResolveRelativePath<TRouteInfo['id'], TTo>,
51
- >(
52
- matchLocation: CheckRelativePath<
53
- TAllRouteInfo,
54
- TRouteInfo['fullPath'],
55
- NoInfer<TTo>
56
- > &
57
- Omit<ToOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo>, 'from'>,
58
- opts?: MatchRouteOptions,
59
- ) => RouteInfoByPath<TAllRouteInfo, TResolved>['allParams']
60
- navigate: <TTo extends string = '.'>(
61
- options: Omit<
62
- LinkOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo>,
63
- 'from'
64
- >,
65
- ) => Promise<void>
66
44
  action: unknown extends TRouteInfo['actionResponse']
67
45
  ?
68
46
  | Action<TRouteInfo['actionPayload'], TRouteInfo['actionResponse']>
@@ -83,6 +61,30 @@ export interface Route<
83
61
  TRouteInfo['allParams'],
84
62
  TRouteInfo['routeLoaderData']
85
63
  >
64
+ // buildLink: <TTo extends string = '.'>(
65
+ // options: Omit<
66
+ // LinkOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo>,
67
+ // 'from'
68
+ // >,
69
+ // ) => LinkInfo
70
+ // matchRoute: <
71
+ // TTo extends string = '.',
72
+ // TResolved extends string = ResolveRelativePath<TRouteInfo['id'], TTo>,
73
+ // >(
74
+ // matchLocation: CheckRelativePath<
75
+ // TAllRouteInfo,
76
+ // TRouteInfo['fullPath'],
77
+ // NoInfer<TTo>
78
+ // > &
79
+ // Omit<ToOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo>, 'from'>,
80
+ // opts?: MatchRouteOptions,
81
+ // ) => RouteInfoByPath<TAllRouteInfo, TResolved>['allParams']
82
+ // navigate: <TTo extends string = '.'>(
83
+ // options: Omit<
84
+ // LinkOptions<TAllRouteInfo, TRouteInfo['fullPath'], TTo>,
85
+ // 'from'
86
+ // >,
87
+ // ) => Promise<void>
86
88
  }
87
89
 
88
90
  export function createRoute<
@@ -92,141 +94,159 @@ export function createRoute<
92
94
  >(
93
95
  routeConfig: RouteConfig,
94
96
  options: TRouteInfo['options'],
97
+ originalIndex: number,
95
98
  parent: undefined | Route<TAllRouteInfo, any>,
96
99
  router: Router<TAllRouteInfo['routeConfig'], TAllRouteInfo, TRouterContext>,
97
100
  ): Route<TAllRouteInfo, TRouteInfo, TRouterContext> {
98
101
  const { id, routeId, path: routePath, fullPath } = routeConfig
99
102
 
100
- const action =
101
- router.state.actions[id] ||
102
- (() => {
103
- router.state.actions[id] = {
104
- submissions: [],
105
- submit: async <T, U>(
106
- submission: T,
107
- actionOpts?: { invalidate?: boolean; multi?: boolean },
108
- ) => {
109
- if (!route) {
110
- return
111
- }
112
-
113
- const invalidate = actionOpts?.invalidate ?? true
114
-
115
- if (!actionOpts?.multi) {
116
- action.submissions = action.submissions.filter((d) => d.isMulti)
117
- }
118
-
119
- const actionState: ActionState<T, U> = {
120
- submittedAt: Date.now(),
121
- status: 'pending',
122
- submission,
123
- isMulti: !!actionOpts?.multi,
124
- }
125
-
126
- action.current = actionState
127
- action.latest = actionState
128
- action.submissions.push(actionState)
129
-
130
- router.notify()
131
-
132
- try {
133
- const res = await route.options.action?.(submission)
134
- actionState.data = res as U
135
-
136
- if (invalidate) {
137
- router.invalidateRoute({ to: '.', fromCurrent: true })
138
- await router.reload()
139
- }
140
- actionState.status = 'success'
141
- return res
142
- } catch (err) {
143
- console.log('tanner')
144
- console.error(err)
145
- actionState.error = err
146
- actionState.status = 'error'
147
- } finally {
148
- router.notify()
149
- }
150
- },
151
- }
152
- return router.state.actions[id]!
153
- })()
154
-
155
- const loader =
156
- router.state.loaders[id] ||
157
- (() => {
158
- router.state.loaders[id] = {
159
- pending: [],
160
- fetch: (async (loaderContext: LoaderContext<any, any>) => {
161
- if (!route) {
162
- return
163
- }
164
-
165
- const loaderState: LoaderState<any, any> = {
166
- loadedAt: Date.now(),
167
- loaderContext,
168
- }
169
-
170
- loader.current = loaderState
171
- loader.latest = loaderState
172
- loader.pending.push(loaderState)
173
-
174
- // router.state = {
175
- // ...router.state,
176
- // currentAction: loaderState,
177
- // latestAction: loaderState,
178
- // }
179
-
180
- router.notify()
181
-
182
- try {
183
- return await route.options.loader?.(loaderContext)
184
- } finally {
185
- loader.pending = loader.pending.filter((d) => d !== loaderState)
186
- // router.removeActionQueue.push({ loader, loaderState })
187
- router.notify()
188
- }
189
- }) as any,
190
- }
191
- return router.state.loaders[id]!
192
- })()
193
-
194
103
  let route: Route<TAllRouteInfo, TRouteInfo, TRouterContext> = {
195
104
  routeInfo: undefined!,
196
105
  routeId: id,
197
106
  routeRouteId: routeId,
107
+ originalIndex,
198
108
  routePath,
199
109
  fullPath,
200
110
  options,
201
111
  router,
202
112
  childRoutes: undefined!,
203
113
  parentRoute: parent,
204
- action,
205
- loader: loader as any,
206
-
207
- buildLink: (options) => {
208
- return router.buildLink({
209
- ...options,
210
- from: fullPath,
211
- } as any) as any
212
- },
114
+ get action() {
115
+ let action =
116
+ router.store.actions[id] ||
117
+ (() => {
118
+ router.setStore((s) => {
119
+ s.actions[id] = {
120
+ submissions: [],
121
+ submit: async <T, U>(
122
+ submission: T,
123
+ actionOpts?: { invalidate?: boolean; multi?: boolean },
124
+ ) => {
125
+ if (!route) {
126
+ return
127
+ }
128
+
129
+ const invalidate = actionOpts?.invalidate ?? true
130
+
131
+ const [actionStore, setActionStore] = createStore<
132
+ ActionState<T, U>
133
+ >({
134
+ submittedAt: Date.now(),
135
+ status: 'pending',
136
+ submission,
137
+ isMulti: !!actionOpts?.multi,
138
+ })
139
+
140
+ router.setStore((s) => {
141
+ if (!actionOpts?.multi) {
142
+ s.actions[id]!.submissions = action.submissions.filter(
143
+ (d) => d.isMulti,
144
+ )
145
+ }
146
+
147
+ s.actions[id]!.current = actionStore
148
+ s.actions[id]!.latest = actionStore
149
+ s.actions[id]!.submissions.push(actionStore)
150
+ })
151
+
152
+ try {
153
+ const res = await route.options.action?.(submission)
154
+
155
+ setActionStore((s) => {
156
+ s.data = res as U
157
+ })
158
+
159
+ if (invalidate) {
160
+ router.invalidateRoute({ to: '.', fromCurrent: true })
161
+ await router.reload()
162
+ }
163
+
164
+ setActionStore((s) => {
165
+ s.status = 'success'
166
+ })
167
+
168
+ return res
169
+ } catch (err) {
170
+ console.error(err)
171
+ setActionStore((s) => {
172
+ s.error = err
173
+ s.status = 'error'
174
+ })
175
+ }
176
+ },
177
+ }
178
+ })
213
179
 
214
- navigate: (options) => {
215
- return router.navigate({
216
- ...options,
217
- from: fullPath,
218
- } as any) as any
180
+ return router.store.actions[id]!
181
+ })()
182
+
183
+ return action
219
184
  },
185
+ get loader() {
186
+ let loader =
187
+ router.store.loaders[id] ||
188
+ (() => {
189
+ router.setStore((s) => {
190
+ s.loaders[id] = {
191
+ pending: [],
192
+ fetch: (async (loaderContext: LoaderContext<any, any>) => {
193
+ if (!route) {
194
+ return
195
+ }
196
+
197
+ const loaderState: LoaderState<any, any> = {
198
+ loadedAt: Date.now(),
199
+ loaderContext,
200
+ }
201
+
202
+ router.setStore((s) => {
203
+ s.loaders[id]!.current = loaderState
204
+ s.loaders[id]!.latest = loaderState
205
+ s.loaders[id]!.pending.push(loaderState)
206
+ })
207
+
208
+ try {
209
+ return await route.options.loader?.(loaderContext)
210
+ } finally {
211
+ router.setStore((s) => {
212
+ s.loaders[id]!.pending = s.loaders[id]!.pending.filter(
213
+ (d) => d !== loaderState,
214
+ )
215
+ })
216
+ }
217
+ }) as any,
218
+ }
219
+ })
220
220
 
221
- matchRoute: (matchLocation, opts) => {
222
- return router.matchRoute(
223
- {
224
- ...matchLocation,
225
- from: fullPath,
226
- } as any,
227
- opts,
228
- ) as any
221
+ return router.store.loaders[id]!
222
+ })()
223
+
224
+ return loader as any
229
225
  },
226
+
227
+ // buildLink: (options) => {
228
+ // return router.buildLink({
229
+ // ...options,
230
+ // from: fullPath,
231
+ // } as any) as any
232
+ // },
233
+
234
+ // navigate: (options) => {
235
+ // return router.navigate({
236
+ // ...options,
237
+ // from: fullPath,
238
+ // } as any) as any
239
+ // },
240
+
241
+ // matchRoute: (matchLocation, opts) => {
242
+ // return router.matchRoute(
243
+ // {
244
+ // ...matchLocation,
245
+ // from: fullPath,
246
+ // } as any,
247
+ // opts,
248
+ // ) as any
249
+ // },
230
250
  }
231
251
 
232
252
  router.options.createRoute?.({ router, route })
@@ -123,12 +123,17 @@ export type RouteOptions<
123
123
  // An asynchronous function made available to the route for performing asynchronous or mutative actions that
124
124
  // might invalidate the route's data.
125
125
  action?: ActionFn<TActionPayload, TActionResponse>
126
- // This async function is called before a route is loaded. If an error is thrown, the navigation is cancelled.
127
- // If you want to redirect instead, throw a call to the `router.navigate()` function
126
+ // This async function is called before a route is loaded.
127
+ // If an error is thrown here, the route's loader will not be called.
128
+ // If thrown during a navigation, the navigation will be cancelled and the error will be passed to the `onLoadError` function.
129
+ // If thrown during a preload event, the error will be logged to the console.
128
130
  beforeLoad?: (opts: {
129
131
  router: Router<any, any, unknown>
130
132
  match: RouteMatch
131
133
  }) => Promise<void> | void
134
+ // This function will be called if the route's loader throws an error **during an attempted navigation**.
135
+ // If you want to redirect due to an error, call `router.navigate()` from within this function.
136
+ onLoadError?: (err: any) => void
132
137
  // This function is called
133
138
  // when moving from an inactive state to an active one. Likewise, when moving from
134
139
  // an active to an inactive state, the return function (if provided) is called.