@tanstack/router-core 0.0.1-beta.36 → 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.
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.36",
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,140 +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.error(err)
144
- actionState.error = err
145
- actionState.status = 'error'
146
- } finally {
147
- router.notify()
148
- }
149
- },
150
- }
151
- return router.state.actions[id]!
152
- })()
153
-
154
- const loader =
155
- router.state.loaders[id] ||
156
- (() => {
157
- router.state.loaders[id] = {
158
- pending: [],
159
- fetch: (async (loaderContext: LoaderContext<any, any>) => {
160
- if (!route) {
161
- return
162
- }
163
-
164
- const loaderState: LoaderState<any, any> = {
165
- loadedAt: Date.now(),
166
- loaderContext,
167
- }
168
-
169
- loader.current = loaderState
170
- loader.latest = loaderState
171
- loader.pending.push(loaderState)
172
-
173
- // router.state = {
174
- // ...router.state,
175
- // currentAction: loaderState,
176
- // latestAction: loaderState,
177
- // }
178
-
179
- router.notify()
180
-
181
- try {
182
- return await route.options.loader?.(loaderContext)
183
- } finally {
184
- loader.pending = loader.pending.filter((d) => d !== loaderState)
185
- // router.removeActionQueue.push({ loader, loaderState })
186
- router.notify()
187
- }
188
- }) as any,
189
- }
190
- return router.state.loaders[id]!
191
- })()
192
-
193
103
  let route: Route<TAllRouteInfo, TRouteInfo, TRouterContext> = {
194
104
  routeInfo: undefined!,
195
105
  routeId: id,
196
106
  routeRouteId: routeId,
107
+ originalIndex,
197
108
  routePath,
198
109
  fullPath,
199
110
  options,
200
111
  router,
201
112
  childRoutes: undefined!,
202
113
  parentRoute: parent,
203
- action,
204
- loader: loader as any,
205
-
206
- buildLink: (options) => {
207
- return router.buildLink({
208
- ...options,
209
- from: fullPath,
210
- } as any) as any
211
- },
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
+ })
212
179
 
213
- navigate: (options) => {
214
- return router.navigate({
215
- ...options,
216
- from: fullPath,
217
- } as any) as any
180
+ return router.store.actions[id]!
181
+ })()
182
+
183
+ return action
218
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
+ })
219
220
 
220
- matchRoute: (matchLocation, opts) => {
221
- return router.matchRoute(
222
- {
223
- ...matchLocation,
224
- from: fullPath,
225
- } as any,
226
- opts,
227
- ) as any
221
+ return router.store.loaders[id]!
222
+ })()
223
+
224
+ return loader as any
228
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
+ // },
229
250
  }
230
251
 
231
252
  router.options.createRoute?.({ router, route })