@benjavicente/angular-router-experimental 1.142.11

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 (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +15 -0
  3. package/dist/fesm2022/tanstack-angular-router-experimental-experimental.mjs +920 -0
  4. package/dist/fesm2022/tanstack-angular-router-experimental.mjs +4131 -0
  5. package/dist/types/tanstack-angular-router-experimental-experimental.d.ts +110 -0
  6. package/dist/types/tanstack-angular-router-experimental.d.ts +733 -0
  7. package/experimental/injectRouteErrorHandler.ts +51 -0
  8. package/experimental/public_api.ts +8 -0
  9. package/package.json +98 -0
  10. package/src/DefaultNotFound.ts +9 -0
  11. package/src/Link.ts +352 -0
  12. package/src/Match.ts +338 -0
  13. package/src/Matches.ts +37 -0
  14. package/src/RouterProvider.ts +162 -0
  15. package/src/document/build-match-managed-document.ts +308 -0
  16. package/src/document/document-dehydration.ts +27 -0
  17. package/src/document/document-equality.ts +29 -0
  18. package/src/document/document-router-token.ts +6 -0
  19. package/src/document/index.ts +33 -0
  20. package/src/document/install-unified-document-sync.ts +108 -0
  21. package/src/document/managed-document-types.ts +36 -0
  22. package/src/document/managed-dom.ts +307 -0
  23. package/src/document/provide-tanstack-body-managed-tags.ts +78 -0
  24. package/src/document/provide-tanstack-document-title.ts +59 -0
  25. package/src/document/provide-tanstack-document.ts +62 -0
  26. package/src/document/provide-tanstack-head-managed-tags.ts +63 -0
  27. package/src/fileRoute.ts +232 -0
  28. package/src/index.ts +173 -0
  29. package/src/injectBlocker.ts +196 -0
  30. package/src/injectCanGoBack.ts +11 -0
  31. package/src/injectErrorState.ts +21 -0
  32. package/src/injectIntersectionObserver.ts +28 -0
  33. package/src/injectLoaderData.ts +49 -0
  34. package/src/injectLoaderDeps.ts +45 -0
  35. package/src/injectLocation.ts +38 -0
  36. package/src/injectMatch.ts +122 -0
  37. package/src/injectMatchRoute.ts +58 -0
  38. package/src/injectMatches.ts +79 -0
  39. package/src/injectNavigate.ts +24 -0
  40. package/src/injectParams.ts +71 -0
  41. package/src/injectRouteContext.ts +31 -0
  42. package/src/injectRouter.ts +17 -0
  43. package/src/injectRouterState.ts +53 -0
  44. package/src/injectSearch.ts +71 -0
  45. package/src/injectStore.ts +87 -0
  46. package/src/matchInjectorToken.ts +23 -0
  47. package/src/renderer/injectIsCatchingError.ts +40 -0
  48. package/src/renderer/injectRender.ts +69 -0
  49. package/src/route.ts +641 -0
  50. package/src/router.ts +141 -0
  51. package/src/routerInjectionToken.ts +24 -0
  52. package/src/routerStores.ts +107 -0
  53. package/src/ssr-scroll-restoration.ts +48 -0
  54. package/src/transitioner.ts +255 -0
@@ -0,0 +1,232 @@
1
+ import { createRoute } from './route'
2
+
3
+ import { injectMatch } from './injectMatch'
4
+ import { injectLoaderDeps } from './injectLoaderDeps'
5
+ import { injectLoaderData } from './injectLoaderData'
6
+ import { injectSearch } from './injectSearch'
7
+ import { injectParams } from './injectParams'
8
+ import { injectNavigate } from './injectNavigate'
9
+ import { injectRouter } from './injectRouter'
10
+ import { injectRouteContext } from './injectRouteContext'
11
+ import type { InjectParamsRoute } from './injectParams'
12
+ import type { InjectMatchRoute } from './injectMatch'
13
+ import type { InjectSearchRoute } from './injectSearch'
14
+ import type {
15
+ AnyContext,
16
+ AnyRoute,
17
+ AnyRouter,
18
+ ConstrainLiteral,
19
+ FileBaseRouteOptions,
20
+ FileRoutesByPath,
21
+ LazyRouteOptions,
22
+ Register,
23
+ RegisteredRouter,
24
+ ResolveParams,
25
+ Route,
26
+ RouteById,
27
+ RouteConstraints,
28
+ RouteIds,
29
+ UpdatableRouteOptions,
30
+ UseNavigateResult,
31
+ } from '@benjavicente/router-core'
32
+ import type { InjectLoaderDepsRoute } from './injectLoaderDeps'
33
+ import type { InjectLoaderDataRoute } from './injectLoaderData'
34
+ import type { InjectRouteContextRoute } from './injectRouteContext'
35
+
36
+ export function createFileRoute<
37
+ TFilePath extends keyof FileRoutesByPath,
38
+ TParentRoute extends AnyRoute = FileRoutesByPath[TFilePath]['parentRoute'],
39
+ TId extends RouteConstraints['TId'] = FileRoutesByPath[TFilePath]['id'],
40
+ TPath extends RouteConstraints['TPath'] = FileRoutesByPath[TFilePath]['path'],
41
+ TFullPath extends
42
+ RouteConstraints['TFullPath'] = FileRoutesByPath[TFilePath]['fullPath'],
43
+ >(
44
+ path?: TFilePath,
45
+ ): InternalFileRouteFactory<
46
+ TFilePath,
47
+ TParentRoute,
48
+ TId,
49
+ TPath,
50
+ TFullPath
51
+ >['createRoute'] {
52
+ if (typeof path === 'object') {
53
+ return new InternalFileRouteFactory<
54
+ TFilePath,
55
+ TParentRoute,
56
+ TId,
57
+ TPath,
58
+ TFullPath
59
+ >().createRoute(path) as any
60
+ }
61
+ return new InternalFileRouteFactory<
62
+ TFilePath,
63
+ TParentRoute,
64
+ TId,
65
+ TPath,
66
+ TFullPath
67
+ >().createRoute
68
+ }
69
+
70
+ class InternalFileRouteFactory<
71
+ TFilePath extends keyof FileRoutesByPath,
72
+ TParentRoute extends AnyRoute = FileRoutesByPath[TFilePath]['parentRoute'],
73
+ TId extends RouteConstraints['TId'] = FileRoutesByPath[TFilePath]['id'],
74
+ TPath extends RouteConstraints['TPath'] = FileRoutesByPath[TFilePath]['path'],
75
+ TFullPath extends
76
+ RouteConstraints['TFullPath'] = FileRoutesByPath[TFilePath]['fullPath'],
77
+ > {
78
+ createRoute = <
79
+ TRegister = Register,
80
+ TSearchValidator = undefined,
81
+ TParams = ResolveParams<TPath>,
82
+ TRouteContextFn = AnyContext,
83
+ TBeforeLoadFn = AnyContext,
84
+ TLoaderDeps extends Record<string, any> = {},
85
+ TLoaderFn = undefined,
86
+ TChildren = unknown,
87
+ TSSR = unknown,
88
+ TMiddlewares = unknown,
89
+ THandlers = undefined,
90
+ >(
91
+ options?: FileBaseRouteOptions<
92
+ TRegister,
93
+ TParentRoute,
94
+ TId,
95
+ TPath,
96
+ TSearchValidator,
97
+ TParams,
98
+ TLoaderDeps,
99
+ TLoaderFn,
100
+ AnyContext,
101
+ TRouteContextFn,
102
+ TBeforeLoadFn,
103
+ AnyContext,
104
+ TSSR,
105
+ TMiddlewares,
106
+ THandlers
107
+ > &
108
+ UpdatableRouteOptions<
109
+ TParentRoute,
110
+ TId,
111
+ TFullPath,
112
+ TParams,
113
+ TSearchValidator,
114
+ TLoaderFn,
115
+ TLoaderDeps,
116
+ AnyContext,
117
+ TRouteContextFn,
118
+ TBeforeLoadFn
119
+ >,
120
+ ): Route<
121
+ TRegister,
122
+ TParentRoute,
123
+ TPath,
124
+ TFullPath,
125
+ TFilePath,
126
+ TId,
127
+ TSearchValidator,
128
+ TParams,
129
+ AnyContext,
130
+ TRouteContextFn,
131
+ TBeforeLoadFn,
132
+ TLoaderDeps,
133
+ TLoaderFn,
134
+ TChildren,
135
+ unknown,
136
+ TSSR,
137
+ TMiddlewares,
138
+ THandlers
139
+ > => {
140
+ const route = createRoute(options as any)
141
+ ; (route as any).isRoot = false
142
+ return route as any
143
+ }
144
+ }
145
+
146
+ declare module '@benjavicente/router-core' {
147
+ export interface LazyRoute<in out TRoute extends AnyRoute> {
148
+ injectMatch: InjectMatchRoute<TRoute['id']>
149
+ injectRouteContext: InjectRouteContextRoute<TRoute['id']>
150
+ injectSearch: InjectSearchRoute<TRoute['id']>
151
+ injectParams: InjectParamsRoute<TRoute['id']>
152
+ injectLoaderDeps: InjectLoaderDepsRoute<TRoute['id']>
153
+ injectLoaderData: InjectLoaderDataRoute<TRoute['id']>
154
+ injectNavigate: () => UseNavigateResult<TRoute['fullPath']>
155
+ }
156
+ }
157
+
158
+ export class LazyRoute<TRoute extends AnyRoute> {
159
+ options: {
160
+ id: string
161
+ } & LazyRouteOptions
162
+
163
+ constructor(
164
+ opts: {
165
+ id: string
166
+ } & LazyRouteOptions,
167
+ ) {
168
+ this.options = opts
169
+ }
170
+
171
+ injectMatch: InjectMatchRoute<TRoute['id']> = (opts) => {
172
+ return injectMatch({
173
+ select: opts?.select,
174
+ from: this.options.id,
175
+ } as any) as any
176
+ }
177
+
178
+ injectRouteContext: InjectRouteContextRoute<TRoute['id']> = (opts) => {
179
+ return injectRouteContext({ ...(opts as any), from: this.options.id }) as any
180
+ }
181
+
182
+ injectSearch: InjectSearchRoute<TRoute['id']> = (opts) => {
183
+ return injectSearch({
184
+ select: opts?.select,
185
+ from: this.options.id,
186
+ } as any) as any
187
+ }
188
+
189
+ injectParams: InjectParamsRoute<TRoute['id']> = (opts) => {
190
+ return injectParams({
191
+ select: opts?.select,
192
+ from: this.options.id,
193
+ } as any) as any
194
+ }
195
+
196
+ injectLoaderDeps: InjectLoaderDepsRoute<TRoute['id']> = (opts) => {
197
+ return injectLoaderDeps({ ...opts, from: this.options.id } as any)
198
+ }
199
+
200
+ injectLoaderData: InjectLoaderDataRoute<TRoute['id']> = (opts) => {
201
+ return injectLoaderData({ ...opts, from: this.options.id } as any)
202
+ }
203
+
204
+ injectNavigate = (): UseNavigateResult<TRoute['fullPath']> => {
205
+ const router = injectRouter()
206
+ return injectNavigate({ from: router.routesById[this.options.id].fullPath })
207
+ }
208
+ }
209
+
210
+ export function createLazyRoute<
211
+ TRouter extends AnyRouter = RegisteredRouter,
212
+ TId extends string = string,
213
+ TRoute extends AnyRoute = RouteById<TRouter['routeTree'], TId>,
214
+ >(id: ConstrainLiteral<TId, RouteIds<TRouter['routeTree']>>) {
215
+ return (opts: LazyRouteOptions) => {
216
+ return new LazyRoute<TRoute>({
217
+ id: id,
218
+ ...opts,
219
+ })
220
+ }
221
+ }
222
+
223
+ export function createLazyFileRoute<
224
+ TFilePath extends keyof FileRoutesByPath,
225
+ TRoute extends FileRoutesByPath[TFilePath]['preLoaderRoute'],
226
+ >(id: TFilePath): (opts: LazyRouteOptions) => LazyRoute<TRoute> {
227
+ if (typeof id === 'object') {
228
+ return new LazyRoute<TRoute>(id) as any
229
+ }
230
+
231
+ return (opts: LazyRouteOptions) => new LazyRoute<TRoute>({ id, ...opts })
232
+ }
package/src/index.ts ADDED
@@ -0,0 +1,173 @@
1
+ // Router
2
+ export {
3
+ createRouter,
4
+ Router,
5
+ type AngularInjectFn,
6
+ type AngularRouterContext,
7
+ } from './router'
8
+
9
+ // Route creation
10
+ export {
11
+ createRoute,
12
+ createRootRoute,
13
+ createRootRouteWithContext,
14
+ createRouteMask,
15
+ getRouteApi,
16
+ Route,
17
+ RootRoute,
18
+ NotFoundRoute,
19
+ RouteApi,
20
+ type AnyRootRoute,
21
+ type RouteComponent,
22
+ type ErrorRouteComponent,
23
+ type NotFoundRouteComponent,
24
+ } from './route'
25
+
26
+ export {
27
+ createFileRoute,
28
+ LazyRoute,
29
+ createLazyRoute,
30
+ createLazyFileRoute,
31
+ } from './fileRoute'
32
+
33
+ // Router Provider
34
+ export { RouterProvider, provideTanstackRouter } from './RouterProvider'
35
+ export {
36
+ provideHeadContent,
37
+ provideTanstackDocument,
38
+ provideTanstackDocumentTitle,
39
+ provideTanstackHeadManagedTags,
40
+ provideTanstackBodyManagedTags,
41
+ type TanstackDocumentFeatures,
42
+ buildMatchManagedDocumentContent,
43
+ buildManagedDocumentContent,
44
+ } from './document'
45
+
46
+ // Components
47
+ export { Outlet, RouteMatch } from './Match'
48
+ export { Matches } from './Matches'
49
+ export { injectSsrScrollRestorationScript } from './ssr-scroll-restoration'
50
+ export {
51
+ injectMatches,
52
+ injectParentMatches,
53
+ injectChildMatches,
54
+ type InjectMatchesBaseOptions,
55
+ type InjectMatchesResult,
56
+ } from './injectMatches'
57
+ export { injectMatchRoute, type InjectMatchRouteOptions } from './injectMatchRoute'
58
+
59
+ // Injection functions
60
+ export { injectRouter } from './injectRouter'
61
+
62
+ export {
63
+ injectRouterState,
64
+ type InjectRouterStateOptions,
65
+ type InjectRouterStateResult,
66
+ } from './injectRouterState'
67
+
68
+ export { injectNavigate } from './injectNavigate'
69
+
70
+ export {
71
+ injectMatch,
72
+ type InjectMatchOptions,
73
+ type InjectMatchResult,
74
+ type InjectMatchRoute,
75
+ type InjectMatchBaseOptions,
76
+ } from './injectMatch'
77
+
78
+ export {
79
+ injectParams,
80
+ type InjectParamsOptions,
81
+ type InjectParamsRoute,
82
+ type InjectParamsBaseOptions,
83
+ } from './injectParams'
84
+
85
+ export {
86
+ injectSearch,
87
+ type InjectSearchOptions,
88
+ type InjectSearchRoute,
89
+ type InjectSearchBaseOptions,
90
+ } from './injectSearch'
91
+
92
+ export {
93
+ injectLoaderData,
94
+ type InjectLoaderDataOptions,
95
+ type InjectLoaderDataRoute,
96
+ type InjectLoaderDataBaseOptions,
97
+ } from './injectLoaderData'
98
+
99
+ export {
100
+ injectLoaderDeps,
101
+ type InjectLoaderDepsOptions,
102
+ type InjectLoaderDepsRoute,
103
+ type InjectLoaderDepsBaseOptions,
104
+ } from './injectLoaderDeps'
105
+
106
+ export {
107
+ injectRouteContext,
108
+ type InjectRouteContextRoute,
109
+ } from './injectRouteContext'
110
+
111
+ export {
112
+ injectLocation,
113
+ type InjectLocationOptions,
114
+ type InjectLocationResult,
115
+ } from './injectLocation'
116
+
117
+ export {
118
+ injectBlocker,
119
+ type InjectBlockerOpts,
120
+ type UseBlockerOpts,
121
+ type ShouldBlockFn,
122
+ } from './injectBlocker'
123
+
124
+ export { injectCanGoBack } from './injectCanGoBack'
125
+
126
+ export { injectErrorState } from './injectErrorState'
127
+
128
+ export { injectStore } from './injectStore'
129
+
130
+ // Link
131
+ export { type LinkOptions as LinkInputOptions, Link } from './Link'
132
+
133
+ // Core re-exports
134
+ export {
135
+ lazyFn,
136
+ notFound,
137
+ redirect,
138
+ isRedirect,
139
+ retainSearchParams,
140
+ createRouterConfig,
141
+ } from '@benjavicente/router-core'
142
+
143
+ // History utilities
144
+ export {
145
+ createHistory,
146
+ createBrowserHistory,
147
+ createHashHistory,
148
+ createMemoryHistory,
149
+ } from '@benjavicente/history'
150
+
151
+ export type {
152
+ BlockerFn,
153
+ HistoryLocation,
154
+ RouterHistory,
155
+ ParsedPath,
156
+ HistoryState,
157
+ } from '@benjavicente/history'
158
+
159
+ // Re-export types from router-core that are commonly used (FileRoutesByPath augmented by routeTree.gen.ts via declare module '@benjavicente/router-core')
160
+ export type {
161
+ AnyRouter,
162
+ RegisteredRouter,
163
+ RouterState,
164
+ LinkOptions,
165
+ NavigateOptions,
166
+ RouteOptions,
167
+ RootRouteOptions,
168
+ Register,
169
+ RouterContextOptions,
170
+ FileRoutesByPath,
171
+ CreateFileRoute,
172
+ CreateLazyFileRoute,
173
+ } from '@benjavicente/router-core'
@@ -0,0 +1,196 @@
1
+ import * as Angular from '@angular/core'
2
+ import { injectRouter } from './injectRouter'
3
+ import type {
4
+ BlockerFnArgs,
5
+ HistoryAction,
6
+ HistoryLocation,
7
+ } from '@benjavicente/history'
8
+ import type {
9
+ AnyRoute,
10
+ AnyRouter,
11
+ ParseRoute,
12
+ RegisteredRouter,
13
+ } from '@benjavicente/router-core'
14
+
15
+ interface ShouldBlockFnLocation<
16
+ out TRouteId,
17
+ out TFullPath,
18
+ out TAllParams,
19
+ out TFullSearchSchema,
20
+ > {
21
+ routeId: TRouteId
22
+ fullPath: TFullPath
23
+ pathname: string
24
+ params: TAllParams
25
+ search: TFullSearchSchema
26
+ }
27
+
28
+ type AnyShouldBlockFnLocation = ShouldBlockFnLocation<any, any, any, any>
29
+
30
+ type MakeShouldBlockFnLocationUnion<
31
+ TRouter extends AnyRouter = RegisteredRouter,
32
+ TRoute extends AnyRoute = ParseRoute<TRouter['routeTree']>,
33
+ > = TRoute extends any
34
+ ? ShouldBlockFnLocation<
35
+ TRoute['id'],
36
+ TRoute['fullPath'],
37
+ TRoute['types']['allParams'],
38
+ TRoute['types']['fullSearchSchema']
39
+ >
40
+ : never
41
+
42
+ type BlockerResolver<TRouter extends AnyRouter = RegisteredRouter> =
43
+ | {
44
+ status: 'blocked'
45
+ current: MakeShouldBlockFnLocationUnion<TRouter>
46
+ next: MakeShouldBlockFnLocationUnion<TRouter>
47
+ action: HistoryAction
48
+ proceed: () => void
49
+ reset: () => void
50
+ }
51
+ | {
52
+ status: 'idle'
53
+ current: undefined
54
+ next: undefined
55
+ action: undefined
56
+ proceed: undefined
57
+ reset: undefined
58
+ }
59
+
60
+ type ShouldBlockFnArgs<TRouter extends AnyRouter = RegisteredRouter> = {
61
+ current: MakeShouldBlockFnLocationUnion<TRouter>
62
+ next: MakeShouldBlockFnLocationUnion<TRouter>
63
+ action: HistoryAction
64
+ }
65
+
66
+ export type ShouldBlockFn<TRouter extends AnyRouter = RegisteredRouter> = (
67
+ args: ShouldBlockFnArgs<TRouter>,
68
+ ) => boolean | Promise<boolean>
69
+
70
+ export type UseBlockerOpts<
71
+ TRouter extends AnyRouter = RegisteredRouter,
72
+ TWithResolver extends boolean = boolean,
73
+ > = {
74
+ shouldBlockFn: ShouldBlockFn<TRouter>
75
+ enableBeforeUnload?: boolean | (() => boolean)
76
+ disabled?: boolean
77
+ withResolver?: TWithResolver
78
+ }
79
+
80
+ export type InjectBlockerOpts<
81
+ TRouter extends AnyRouter = RegisteredRouter,
82
+ TWithResolver extends boolean = boolean,
83
+ > = {
84
+ shouldBlockFn: ShouldBlockFn<TRouter>
85
+ enableBeforeUnload?: boolean | (() => boolean)
86
+ disabled?: boolean | (() => boolean)
87
+ withResolver?: TWithResolver
88
+ }
89
+
90
+ export function injectBlocker<
91
+ TRouter extends AnyRouter = RegisteredRouter,
92
+ TWithResolver extends boolean = boolean,
93
+ >(
94
+ opts: InjectBlockerOpts<TRouter, TWithResolver>,
95
+ ): TWithResolver extends true
96
+ ? Angular.Signal<BlockerResolver<TRouter>>
97
+ : void {
98
+ const {
99
+ shouldBlockFn,
100
+ enableBeforeUnload = true,
101
+ disabled = false,
102
+ withResolver = false,
103
+ } = opts
104
+ const router = injectRouter()
105
+ const { history } = router
106
+
107
+ const resolver = Angular.signal<BlockerResolver>({
108
+ status: 'idle',
109
+ current: undefined,
110
+ next: undefined,
111
+ action: undefined,
112
+ proceed: undefined,
113
+ reset: undefined,
114
+ })
115
+
116
+ Angular.effect((onCleanup) => {
117
+ const blockerFnComposed = async (blockerFnArgs: BlockerFnArgs) => {
118
+ function getLocation(
119
+ location: HistoryLocation,
120
+ ): AnyShouldBlockFnLocation {
121
+ const parsedLocation = router.parseLocation(location)
122
+ const matchedRoutes = router.getMatchedRoutes(parsedLocation.pathname)
123
+ if (matchedRoutes.foundRoute === undefined) {
124
+ return {
125
+ routeId: '__notFound__',
126
+ fullPath: parsedLocation.pathname,
127
+ pathname: parsedLocation.pathname,
128
+ params: matchedRoutes.routeParams,
129
+ search: parsedLocation.search,
130
+ }
131
+ }
132
+ return {
133
+ routeId: matchedRoutes.foundRoute.id,
134
+ fullPath: matchedRoutes.foundRoute.fullPath,
135
+ pathname: parsedLocation.pathname,
136
+ params: matchedRoutes.routeParams,
137
+ search: parsedLocation.search,
138
+ }
139
+ }
140
+
141
+ const current = getLocation(blockerFnArgs.currentLocation)
142
+ const next = getLocation(blockerFnArgs.nextLocation)
143
+
144
+ if (
145
+ current.routeId === '__notFound__' &&
146
+ next.routeId !== '__notFound__'
147
+ ) {
148
+ return false
149
+ }
150
+
151
+ const shouldBlock = await shouldBlockFn({
152
+ action: blockerFnArgs.action,
153
+ current: current as MakeShouldBlockFnLocationUnion<TRouter>,
154
+ next: next as MakeShouldBlockFnLocationUnion<TRouter>,
155
+ })
156
+ if (!withResolver) {
157
+ return shouldBlock
158
+ }
159
+
160
+ if (!shouldBlock) {
161
+ return false
162
+ }
163
+
164
+ const promise = new Promise<boolean>((resolve) => {
165
+ resolver.set({
166
+ status: 'blocked',
167
+ current: current as MakeShouldBlockFnLocationUnion<TRouter>,
168
+ next: next as MakeShouldBlockFnLocationUnion<TRouter>,
169
+ action: blockerFnArgs.action,
170
+ proceed: () => resolve(false),
171
+ reset: () => resolve(true),
172
+ })
173
+ })
174
+
175
+ const canNavigateAsync = await promise
176
+ resolver.set({
177
+ status: 'idle',
178
+ current: undefined,
179
+ next: undefined,
180
+ action: undefined,
181
+ proceed: undefined,
182
+ reset: undefined,
183
+ })
184
+
185
+ return canNavigateAsync
186
+ }
187
+ const isDisabled = typeof disabled === 'function' ? disabled() : disabled
188
+ const disposeBlock = isDisabled
189
+ ? undefined
190
+ : history.block({ blockerFn: blockerFnComposed, enableBeforeUnload })
191
+
192
+ onCleanup(() => disposeBlock?.())
193
+ })
194
+
195
+ return resolver.asReadonly() as any
196
+ }
@@ -0,0 +1,11 @@
1
+ import { injectRouter } from './injectRouter'
2
+ import { injectStore } from './injectStore'
3
+
4
+ export function injectCanGoBack() {
5
+ const router = injectRouter()
6
+
7
+ return injectStore(
8
+ router.stores.location,
9
+ (location) => location.state.__TSR_index !== 0,
10
+ )
11
+ }
@@ -0,0 +1,21 @@
1
+ import * as Angular from '@angular/core'
2
+
3
+ export const ERROR_STATE_INJECTOR_TOKEN = new Angular.InjectionToken<{
4
+ error: Error
5
+ reset: () => void
6
+ info: { componentStack: string }
7
+ }>('ERROR_STATE_INJECTOR_TOKEN')
8
+
9
+ /**
10
+ * Injects the error state to the error componenet.
11
+ */
12
+
13
+ export function injectErrorState() {
14
+ const errorState = Angular.inject(ERROR_STATE_INJECTOR_TOKEN, {
15
+ optional: true,
16
+ })
17
+ if (!errorState) {
18
+ throw new Error('injectErrorState was called outside of an error component')
19
+ }
20
+ return errorState
21
+ }
@@ -0,0 +1,28 @@
1
+ import * as Angular from '@angular/core'
2
+
3
+ export function injectIntersectionObserver(
4
+ callback: (entry: IntersectionObserverEntry | undefined) => void,
5
+ intersectionObserverOptions: IntersectionObserverInit,
6
+ disabled: () => boolean,
7
+ ) {
8
+ const elementRef = Angular.inject(Angular.ElementRef)
9
+
10
+ Angular.afterRenderEffect((onCleanup) => {
11
+ const isIntersectionObserverAvailable =
12
+ typeof IntersectionObserver === 'function'
13
+
14
+ const element = elementRef.nativeElement as HTMLElement | null
15
+ if (!element || !isIntersectionObserverAvailable || disabled()) return
16
+
17
+ const observer = new IntersectionObserver(
18
+ ([entry]) => callback(entry),
19
+ intersectionObserverOptions,
20
+ )
21
+
22
+ observer.observe(element)
23
+
24
+ onCleanup(() => {
25
+ observer.disconnect()
26
+ })
27
+ })
28
+ }
@@ -0,0 +1,49 @@
1
+ import { injectMatch } from './injectMatch'
2
+ import type * as Angular from '@angular/core'
3
+ import type {
4
+ AnyRouter,
5
+ RegisteredRouter,
6
+ ResolveUseLoaderData,
7
+ StrictOrFrom,
8
+ UseLoaderDataResult,
9
+ } from '@benjavicente/router-core'
10
+
11
+ export interface InjectLoaderDataBaseOptions<
12
+ TRouter extends AnyRouter,
13
+ TFrom,
14
+ TStrict extends boolean,
15
+ TSelected,
16
+ > {
17
+ select?: (match: ResolveUseLoaderData<TRouter, TFrom, TStrict>) => TSelected
18
+ }
19
+
20
+ export type InjectLoaderDataOptions<
21
+ TRouter extends AnyRouter,
22
+ TFrom extends string | undefined,
23
+ TStrict extends boolean,
24
+ TSelected,
25
+ > = StrictOrFrom<TRouter, TFrom, TStrict> &
26
+ InjectLoaderDataBaseOptions<TRouter, TFrom, TStrict, TSelected>
27
+
28
+ export type InjectLoaderDataRoute<out TFrom> = <
29
+ TRouter extends AnyRouter = RegisteredRouter,
30
+ TSelected = unknown,
31
+ >(
32
+ opts?: InjectLoaderDataBaseOptions<TRouter, TFrom, true, TSelected>,
33
+ ) => Angular.Signal<UseLoaderDataResult<TRouter, TFrom, true, TSelected>>
34
+
35
+ export function injectLoaderData<
36
+ TRouter extends AnyRouter = RegisteredRouter,
37
+ const TFrom extends string | undefined = undefined,
38
+ TStrict extends boolean = true,
39
+ TSelected = unknown,
40
+ >(
41
+ opts: InjectLoaderDataOptions<TRouter, TFrom, TStrict, TSelected>,
42
+ ): Angular.Signal<UseLoaderDataResult<TRouter, TFrom, TStrict, TSelected>> {
43
+ return injectMatch({
44
+ from: opts.from!,
45
+ strict: opts.strict as true | undefined,
46
+ select: (s: any) =>
47
+ opts.select ? opts.select(s.loaderData) : s.loaderData,
48
+ } as any) as any
49
+ }