@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.
- package/LICENSE +21 -0
- package/README.md +15 -0
- package/dist/fesm2022/tanstack-angular-router-experimental-experimental.mjs +920 -0
- package/dist/fesm2022/tanstack-angular-router-experimental.mjs +4131 -0
- package/dist/types/tanstack-angular-router-experimental-experimental.d.ts +110 -0
- package/dist/types/tanstack-angular-router-experimental.d.ts +733 -0
- package/experimental/injectRouteErrorHandler.ts +51 -0
- package/experimental/public_api.ts +8 -0
- package/package.json +98 -0
- package/src/DefaultNotFound.ts +9 -0
- package/src/Link.ts +352 -0
- package/src/Match.ts +338 -0
- package/src/Matches.ts +37 -0
- package/src/RouterProvider.ts +162 -0
- package/src/document/build-match-managed-document.ts +308 -0
- package/src/document/document-dehydration.ts +27 -0
- package/src/document/document-equality.ts +29 -0
- package/src/document/document-router-token.ts +6 -0
- package/src/document/index.ts +33 -0
- package/src/document/install-unified-document-sync.ts +108 -0
- package/src/document/managed-document-types.ts +36 -0
- package/src/document/managed-dom.ts +307 -0
- package/src/document/provide-tanstack-body-managed-tags.ts +78 -0
- package/src/document/provide-tanstack-document-title.ts +59 -0
- package/src/document/provide-tanstack-document.ts +62 -0
- package/src/document/provide-tanstack-head-managed-tags.ts +63 -0
- package/src/fileRoute.ts +232 -0
- package/src/index.ts +173 -0
- package/src/injectBlocker.ts +196 -0
- package/src/injectCanGoBack.ts +11 -0
- package/src/injectErrorState.ts +21 -0
- package/src/injectIntersectionObserver.ts +28 -0
- package/src/injectLoaderData.ts +49 -0
- package/src/injectLoaderDeps.ts +45 -0
- package/src/injectLocation.ts +38 -0
- package/src/injectMatch.ts +122 -0
- package/src/injectMatchRoute.ts +58 -0
- package/src/injectMatches.ts +79 -0
- package/src/injectNavigate.ts +24 -0
- package/src/injectParams.ts +71 -0
- package/src/injectRouteContext.ts +31 -0
- package/src/injectRouter.ts +17 -0
- package/src/injectRouterState.ts +53 -0
- package/src/injectSearch.ts +71 -0
- package/src/injectStore.ts +87 -0
- package/src/matchInjectorToken.ts +23 -0
- package/src/renderer/injectIsCatchingError.ts +40 -0
- package/src/renderer/injectRender.ts +69 -0
- package/src/route.ts +641 -0
- package/src/router.ts +141 -0
- package/src/routerInjectionToken.ts +24 -0
- package/src/routerStores.ts +107 -0
- package/src/ssr-scroll-restoration.ts +48 -0
- package/src/transitioner.ts +255 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { injectMatch } from './injectMatch'
|
|
2
|
+
import type * as Angular from '@angular/core'
|
|
3
|
+
import type {
|
|
4
|
+
AnyRouter,
|
|
5
|
+
RegisteredRouter,
|
|
6
|
+
ResolveUseLoaderDeps,
|
|
7
|
+
StrictOrFrom,
|
|
8
|
+
UseLoaderDepsResult,
|
|
9
|
+
} from '@benjavicente/router-core'
|
|
10
|
+
|
|
11
|
+
export interface InjectLoaderDepsBaseOptions<
|
|
12
|
+
TRouter extends AnyRouter,
|
|
13
|
+
TFrom,
|
|
14
|
+
TSelected,
|
|
15
|
+
> {
|
|
16
|
+
select?: (deps: ResolveUseLoaderDeps<TRouter, TFrom>) => TSelected
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type InjectLoaderDepsOptions<
|
|
20
|
+
TRouter extends AnyRouter,
|
|
21
|
+
TFrom extends string | undefined,
|
|
22
|
+
TSelected,
|
|
23
|
+
> = StrictOrFrom<TRouter, TFrom> &
|
|
24
|
+
InjectLoaderDepsBaseOptions<TRouter, TFrom, TSelected>
|
|
25
|
+
|
|
26
|
+
export type InjectLoaderDepsRoute<out TFrom> = <
|
|
27
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
28
|
+
TSelected = unknown,
|
|
29
|
+
>(
|
|
30
|
+
opts?: InjectLoaderDepsBaseOptions<TRouter, TFrom, TSelected>,
|
|
31
|
+
) => Angular.Signal<UseLoaderDepsResult<TRouter, TFrom, TSelected>>
|
|
32
|
+
|
|
33
|
+
export function injectLoaderDeps<
|
|
34
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
35
|
+
const TFrom extends string | undefined = undefined,
|
|
36
|
+
TSelected = unknown,
|
|
37
|
+
>(
|
|
38
|
+
opts: InjectLoaderDepsOptions<TRouter, TFrom, TSelected>,
|
|
39
|
+
): Angular.Signal<UseLoaderDepsResult<TRouter, TFrom, TSelected>> {
|
|
40
|
+
const { select, ...rest } = opts
|
|
41
|
+
return injectMatch({
|
|
42
|
+
...rest,
|
|
43
|
+
select: (s) => (select ? select(s.loaderDeps) : s.loaderDeps),
|
|
44
|
+
}) as any
|
|
45
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { deepEqual } from '@benjavicente/router-core'
|
|
2
|
+
import { injectRouter } from './injectRouter'
|
|
3
|
+
import { injectStore } from './injectStore'
|
|
4
|
+
import type {
|
|
5
|
+
AnyRouter,
|
|
6
|
+
RegisteredRouter,
|
|
7
|
+
RouterState,
|
|
8
|
+
} from '@benjavicente/router-core'
|
|
9
|
+
import type * as Angular from '@angular/core'
|
|
10
|
+
|
|
11
|
+
export interface InjectLocationOptions<TRouter extends AnyRouter, TSelected> {
|
|
12
|
+
select?: (
|
|
13
|
+
location: RouterState<TRouter['routeTree']>['location'],
|
|
14
|
+
) => TSelected
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type InjectLocationResult<
|
|
18
|
+
TRouter extends AnyRouter,
|
|
19
|
+
TSelected,
|
|
20
|
+
> = unknown extends TSelected
|
|
21
|
+
? RouterState<TRouter['routeTree']>['location']
|
|
22
|
+
: TSelected
|
|
23
|
+
|
|
24
|
+
export function injectLocation<
|
|
25
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
26
|
+
TSelected = unknown,
|
|
27
|
+
>(
|
|
28
|
+
opts?: InjectLocationOptions<TRouter, TSelected>,
|
|
29
|
+
): Angular.Signal<InjectLocationResult<TRouter, TSelected>> {
|
|
30
|
+
const router = injectRouter<TRouter>()
|
|
31
|
+
|
|
32
|
+
return injectStore(
|
|
33
|
+
router.stores.location,
|
|
34
|
+
(location) =>
|
|
35
|
+
(opts?.select ? opts.select(location as any) : location) as any,
|
|
36
|
+
{ equal: deepEqual }
|
|
37
|
+
) as Angular.Signal<InjectLocationResult<TRouter, TSelected>>
|
|
38
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import * as Angular from '@angular/core'
|
|
2
|
+
import { deepEqual, invariant } from '@benjavicente/router-core'
|
|
3
|
+
import { MATCH_CONTEXT_INJECTOR_TOKEN } from './matchInjectorToken'
|
|
4
|
+
import { injectRouter } from './injectRouter'
|
|
5
|
+
import { injectStore } from './injectStore'
|
|
6
|
+
import type {
|
|
7
|
+
AnyRouter,
|
|
8
|
+
MakeRouteMatch,
|
|
9
|
+
MakeRouteMatchUnion,
|
|
10
|
+
RegisteredRouter,
|
|
11
|
+
StrictOrFrom,
|
|
12
|
+
ThrowConstraint,
|
|
13
|
+
ThrowOrOptional,
|
|
14
|
+
} from '@benjavicente/router-core'
|
|
15
|
+
|
|
16
|
+
export interface InjectMatchBaseOptions<
|
|
17
|
+
TRouter extends AnyRouter,
|
|
18
|
+
TFrom,
|
|
19
|
+
TStrict extends boolean,
|
|
20
|
+
TThrow extends boolean,
|
|
21
|
+
TSelected,
|
|
22
|
+
> {
|
|
23
|
+
select?: (
|
|
24
|
+
match: MakeRouteMatch<TRouter['routeTree'], TFrom, TStrict>,
|
|
25
|
+
) => TSelected
|
|
26
|
+
shouldThrow?: TThrow
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type InjectMatchRoute<out TFrom> = <
|
|
30
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
31
|
+
TSelected = unknown,
|
|
32
|
+
>(
|
|
33
|
+
opts?: InjectMatchBaseOptions<TRouter, TFrom, true, true, TSelected>,
|
|
34
|
+
) => Angular.Signal<InjectMatchResult<TRouter, TFrom, true, TSelected>>
|
|
35
|
+
|
|
36
|
+
export type InjectMatchOptions<
|
|
37
|
+
TRouter extends AnyRouter,
|
|
38
|
+
TFrom,
|
|
39
|
+
TStrict extends boolean,
|
|
40
|
+
TThrow extends boolean,
|
|
41
|
+
TSelected,
|
|
42
|
+
> = StrictOrFrom<TRouter, TFrom, TStrict> &
|
|
43
|
+
InjectMatchBaseOptions<TRouter, TFrom, TStrict, TThrow, TSelected>
|
|
44
|
+
|
|
45
|
+
export type InjectMatchResult<
|
|
46
|
+
TRouter extends AnyRouter,
|
|
47
|
+
TFrom,
|
|
48
|
+
TStrict extends boolean,
|
|
49
|
+
TSelected,
|
|
50
|
+
> = unknown extends TSelected
|
|
51
|
+
? TStrict extends true
|
|
52
|
+
? MakeRouteMatch<TRouter['routeTree'], TFrom, TStrict>
|
|
53
|
+
: MakeRouteMatchUnion<TRouter>
|
|
54
|
+
: TSelected
|
|
55
|
+
|
|
56
|
+
export function injectMatch<
|
|
57
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
58
|
+
const TFrom extends string | undefined = undefined,
|
|
59
|
+
TStrict extends boolean = true,
|
|
60
|
+
TThrow extends boolean = true,
|
|
61
|
+
TSelected = unknown,
|
|
62
|
+
>(
|
|
63
|
+
opts: InjectMatchOptions<
|
|
64
|
+
TRouter,
|
|
65
|
+
TFrom,
|
|
66
|
+
TStrict,
|
|
67
|
+
ThrowConstraint<TStrict, TThrow>,
|
|
68
|
+
TSelected
|
|
69
|
+
>,
|
|
70
|
+
): Angular.Signal<
|
|
71
|
+
ThrowOrOptional<InjectMatchResult<TRouter, TFrom, TStrict, TSelected>, TThrow>
|
|
72
|
+
> {
|
|
73
|
+
const router = injectRouter<TRouter>()
|
|
74
|
+
const nearestMatch = opts.from
|
|
75
|
+
? undefined
|
|
76
|
+
: Angular.inject(MATCH_CONTEXT_INJECTOR_TOKEN)
|
|
77
|
+
|
|
78
|
+
const pendingRouteIds = injectStore(
|
|
79
|
+
router.stores.pendingRouteIds,
|
|
80
|
+
(s) => s,
|
|
81
|
+
)
|
|
82
|
+
const isTransitioning = injectStore(
|
|
83
|
+
router.stores.isTransitioning,
|
|
84
|
+
(s) => s,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
const match = () => {
|
|
88
|
+
if (opts.from) {
|
|
89
|
+
return router.stores.getMatchStoreByRouteId(opts.from).state
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return nearestMatch?.match()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return Angular.computed(() => {
|
|
96
|
+
const selectedMatch = match()
|
|
97
|
+
|
|
98
|
+
if (selectedMatch !== undefined) {
|
|
99
|
+
return opts.select ? opts.select(selectedMatch as any) : selectedMatch
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const hasPendingMatch = opts.from
|
|
103
|
+
? Boolean(pendingRouteIds()[opts.from])
|
|
104
|
+
: nearestMatch?.hasPending() ?? false
|
|
105
|
+
|
|
106
|
+
if (
|
|
107
|
+
!hasPendingMatch &&
|
|
108
|
+
!isTransitioning() &&
|
|
109
|
+
(opts.shouldThrow ?? true)
|
|
110
|
+
) {
|
|
111
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
112
|
+
throw new Error(
|
|
113
|
+
`Invariant failed: Could not find ${opts.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`,
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
invariant()
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return undefined
|
|
121
|
+
}, { equal: deepEqual }) as any
|
|
122
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as Angular from '@angular/core'
|
|
2
|
+
import { injectRouter } from './injectRouter'
|
|
3
|
+
import { injectStore } from './injectStore'
|
|
4
|
+
import type {
|
|
5
|
+
AnyRouter,
|
|
6
|
+
DeepPartial,
|
|
7
|
+
Expand,
|
|
8
|
+
MakeOptionalPathParams,
|
|
9
|
+
MakeOptionalSearchParams,
|
|
10
|
+
MaskOptions,
|
|
11
|
+
MatchRouteOptions,
|
|
12
|
+
NoInfer,
|
|
13
|
+
RegisteredRouter,
|
|
14
|
+
ResolveRoute,
|
|
15
|
+
ToSubOptionsProps,
|
|
16
|
+
} from '@benjavicente/router-core'
|
|
17
|
+
|
|
18
|
+
export type InjectMatchRouteOptions<
|
|
19
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
20
|
+
TFrom extends string = string,
|
|
21
|
+
TTo extends string | undefined = undefined,
|
|
22
|
+
TMaskFrom extends string = TFrom,
|
|
23
|
+
TMaskTo extends string = '',
|
|
24
|
+
> = ToSubOptionsProps<TRouter, TFrom, TTo> &
|
|
25
|
+
DeepPartial<MakeOptionalSearchParams<TRouter, TFrom, TTo>> &
|
|
26
|
+
DeepPartial<MakeOptionalPathParams<TRouter, TFrom, TTo>> &
|
|
27
|
+
MaskOptions<TRouter, TMaskFrom, TMaskTo> &
|
|
28
|
+
MatchRouteOptions
|
|
29
|
+
|
|
30
|
+
export function injectMatchRoute<
|
|
31
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
32
|
+
>() {
|
|
33
|
+
const router = injectRouter<TRouter>()
|
|
34
|
+
const reactivity = injectStore(router.stores.matchRouteReactivity, (d) => d)
|
|
35
|
+
|
|
36
|
+
return <
|
|
37
|
+
const TFrom extends string = string,
|
|
38
|
+
const TTo extends string | undefined = undefined,
|
|
39
|
+
const TMaskFrom extends string = TFrom,
|
|
40
|
+
const TMaskTo extends string = '',
|
|
41
|
+
>(
|
|
42
|
+
opts: InjectMatchRouteOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>,
|
|
43
|
+
): Angular.Signal<
|
|
44
|
+
false | Expand<ResolveRoute<TRouter, TFrom, NoInfer<TTo>>['types']['allParams']>
|
|
45
|
+
> => {
|
|
46
|
+
return Angular.computed(() => {
|
|
47
|
+
reactivity()
|
|
48
|
+
const { pending, caseSensitive, fuzzy, includeSearch, ...rest } = opts
|
|
49
|
+
|
|
50
|
+
return router.matchRoute(rest as any, {
|
|
51
|
+
pending,
|
|
52
|
+
caseSensitive,
|
|
53
|
+
fuzzy,
|
|
54
|
+
includeSearch,
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as Angular from '@angular/core'
|
|
2
|
+
import { deepEqual } from '@benjavicente/router-core'
|
|
3
|
+
import { injectRouter } from './injectRouter'
|
|
4
|
+
import { injectStore } from './injectStore'
|
|
5
|
+
import { MATCH_CONTEXT_INJECTOR_TOKEN } from './matchInjectorToken'
|
|
6
|
+
import type {
|
|
7
|
+
AnyRouter,
|
|
8
|
+
MakeRouteMatchUnion,
|
|
9
|
+
RegisteredRouter,
|
|
10
|
+
} from '@benjavicente/router-core'
|
|
11
|
+
|
|
12
|
+
export interface InjectMatchesBaseOptions<
|
|
13
|
+
TRouter extends AnyRouter,
|
|
14
|
+
TSelected,
|
|
15
|
+
> {
|
|
16
|
+
select?: (matches: Array<MakeRouteMatchUnion<TRouter>>) => TSelected
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type InjectMatchesResult<
|
|
20
|
+
TRouter extends AnyRouter,
|
|
21
|
+
TSelected,
|
|
22
|
+
> = unknown extends TSelected ? Array<MakeRouteMatchUnion<TRouter>> : TSelected
|
|
23
|
+
|
|
24
|
+
export function injectMatches<
|
|
25
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
26
|
+
TSelected = unknown,
|
|
27
|
+
>(
|
|
28
|
+
opts?: InjectMatchesBaseOptions<TRouter, TSelected>,
|
|
29
|
+
): Angular.Signal<InjectMatchesResult<TRouter, TSelected>> {
|
|
30
|
+
const router = injectRouter<TRouter>()
|
|
31
|
+
const matches = injectStore(router.stores.activeMatchesSnapshot, (value) => {
|
|
32
|
+
return value as Array<MakeRouteMatchUnion<TRouter>>
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
return Angular.computed(() => {
|
|
36
|
+
const currentMatches = matches()
|
|
37
|
+
const result = opts?.select ? opts.select(currentMatches) : currentMatches
|
|
38
|
+
return result as InjectMatchesResult<TRouter, TSelected>
|
|
39
|
+
}, { equal: deepEqual }) as any
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function injectParentMatches<
|
|
43
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
44
|
+
TSelected = unknown,
|
|
45
|
+
>(
|
|
46
|
+
opts?: InjectMatchesBaseOptions<TRouter, TSelected>,
|
|
47
|
+
): Angular.Signal<InjectMatchesResult<TRouter, TSelected>> {
|
|
48
|
+
const nearestMatch = Angular.inject(MATCH_CONTEXT_INJECTOR_TOKEN)
|
|
49
|
+
|
|
50
|
+
return injectMatches({
|
|
51
|
+
select: (matches: Array<MakeRouteMatchUnion<TRouter>>) => {
|
|
52
|
+
const sliced = matches.slice(
|
|
53
|
+
0,
|
|
54
|
+
matches.findIndex((d) => d.id === nearestMatch.matchId()),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
return opts?.select ? opts.select(sliced) : sliced
|
|
58
|
+
},
|
|
59
|
+
} as any)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function injectChildMatches<
|
|
63
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
64
|
+
TSelected = unknown,
|
|
65
|
+
>(
|
|
66
|
+
opts?: InjectMatchesBaseOptions<TRouter, TSelected>,
|
|
67
|
+
): Angular.Signal<InjectMatchesResult<TRouter, TSelected>> {
|
|
68
|
+
const nearestMatch = Angular.inject(MATCH_CONTEXT_INJECTOR_TOKEN)
|
|
69
|
+
|
|
70
|
+
return injectMatches({
|
|
71
|
+
select: (matches: Array<MakeRouteMatchUnion<TRouter>>) => {
|
|
72
|
+
const sliced = matches.slice(
|
|
73
|
+
matches.findIndex((d) => d.id === nearestMatch.matchId()) + 1,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
return opts?.select ? opts.select(sliced) : sliced
|
|
77
|
+
},
|
|
78
|
+
} as any)
|
|
79
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { injectRouter } from './injectRouter'
|
|
2
|
+
import type {
|
|
3
|
+
AnyRouter,
|
|
4
|
+
FromPathOption,
|
|
5
|
+
NavigateOptions,
|
|
6
|
+
RegisteredRouter,
|
|
7
|
+
UseNavigateResult,
|
|
8
|
+
} from '@benjavicente/router-core'
|
|
9
|
+
|
|
10
|
+
export function injectNavigate<
|
|
11
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
12
|
+
TDefaultFrom extends string = string,
|
|
13
|
+
>(_defaultOpts?: {
|
|
14
|
+
from?: FromPathOption<TRouter, TDefaultFrom>
|
|
15
|
+
}): UseNavigateResult<TDefaultFrom> {
|
|
16
|
+
const router = injectRouter()
|
|
17
|
+
|
|
18
|
+
return ((options: NavigateOptions) => {
|
|
19
|
+
return router.navigate({
|
|
20
|
+
...options,
|
|
21
|
+
from: options.from ?? _defaultOpts?.from,
|
|
22
|
+
})
|
|
23
|
+
}) as UseNavigateResult<TDefaultFrom>
|
|
24
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { injectMatch } from './injectMatch'
|
|
2
|
+
import type * as Angular from '@angular/core'
|
|
3
|
+
import type {
|
|
4
|
+
AnyRouter,
|
|
5
|
+
RegisteredRouter,
|
|
6
|
+
ResolveUseParams,
|
|
7
|
+
StrictOrFrom,
|
|
8
|
+
ThrowConstraint,
|
|
9
|
+
ThrowOrOptional,
|
|
10
|
+
UseParamsResult,
|
|
11
|
+
} from '@benjavicente/router-core'
|
|
12
|
+
|
|
13
|
+
export interface InjectParamsBaseOptions<
|
|
14
|
+
TRouter extends AnyRouter,
|
|
15
|
+
TFrom,
|
|
16
|
+
TStrict extends boolean,
|
|
17
|
+
TThrow extends boolean,
|
|
18
|
+
TSelected,
|
|
19
|
+
> {
|
|
20
|
+
select?: (params: ResolveUseParams<TRouter, TFrom, TStrict>) => TSelected
|
|
21
|
+
shouldThrow?: TThrow
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type InjectParamsOptions<
|
|
25
|
+
TRouter extends AnyRouter,
|
|
26
|
+
TFrom extends string | undefined,
|
|
27
|
+
TStrict extends boolean,
|
|
28
|
+
TThrow extends boolean,
|
|
29
|
+
TSelected,
|
|
30
|
+
> = StrictOrFrom<TRouter, TFrom, TStrict> &
|
|
31
|
+
InjectParamsBaseOptions<TRouter, TFrom, TStrict, TThrow, TSelected>
|
|
32
|
+
|
|
33
|
+
export type InjectParamsRoute<out TFrom> = <
|
|
34
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
35
|
+
TSelected = unknown,
|
|
36
|
+
>(
|
|
37
|
+
opts?: InjectParamsBaseOptions<
|
|
38
|
+
TRouter,
|
|
39
|
+
TFrom,
|
|
40
|
+
/* TStrict */ true,
|
|
41
|
+
/* TThrow */ true,
|
|
42
|
+
TSelected
|
|
43
|
+
>,
|
|
44
|
+
) => Angular.Signal<UseParamsResult<TRouter, TFrom, true, TSelected>>
|
|
45
|
+
|
|
46
|
+
export function injectParams<
|
|
47
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
48
|
+
const TFrom extends string | undefined = undefined,
|
|
49
|
+
TStrict extends boolean = true,
|
|
50
|
+
TThrow extends boolean = true,
|
|
51
|
+
TSelected = unknown,
|
|
52
|
+
>(
|
|
53
|
+
opts: InjectParamsOptions<
|
|
54
|
+
TRouter,
|
|
55
|
+
TFrom,
|
|
56
|
+
TStrict,
|
|
57
|
+
ThrowConstraint<TStrict, TThrow>,
|
|
58
|
+
TSelected
|
|
59
|
+
>,
|
|
60
|
+
): Angular.Signal<
|
|
61
|
+
ThrowOrOptional<UseParamsResult<TRouter, TFrom, true, TSelected>, TThrow>
|
|
62
|
+
> {
|
|
63
|
+
return injectMatch({
|
|
64
|
+
from: opts.from!,
|
|
65
|
+
strict: opts.strict,
|
|
66
|
+
shouldThrow: opts.shouldThrow,
|
|
67
|
+
select: (match: any) => {
|
|
68
|
+
return opts.select ? opts.select(match.params) : match.params
|
|
69
|
+
},
|
|
70
|
+
} as any) as Angular.Signal<any>
|
|
71
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { injectMatch } from './injectMatch'
|
|
2
|
+
import type * as Angular from '@angular/core'
|
|
3
|
+
import type {
|
|
4
|
+
AnyRouter,
|
|
5
|
+
RegisteredRouter,
|
|
6
|
+
UseRouteContextBaseOptions,
|
|
7
|
+
UseRouteContextOptions,
|
|
8
|
+
UseRouteContextResult,
|
|
9
|
+
} from '@benjavicente/router-core'
|
|
10
|
+
|
|
11
|
+
export type InjectRouteContextRoute<out TFrom> = <
|
|
12
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
13
|
+
TSelected = unknown,
|
|
14
|
+
>(
|
|
15
|
+
opts?: UseRouteContextBaseOptions<TRouter, TFrom, true, TSelected>,
|
|
16
|
+
) => Angular.Signal<UseRouteContextResult<TRouter, TFrom, true, TSelected>>
|
|
17
|
+
|
|
18
|
+
export function injectRouteContext<
|
|
19
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
20
|
+
const TFrom extends string | undefined = undefined,
|
|
21
|
+
TStrict extends boolean = true,
|
|
22
|
+
TSelected = unknown,
|
|
23
|
+
>(
|
|
24
|
+
opts: UseRouteContextOptions<TRouter, TFrom, TStrict, TSelected>,
|
|
25
|
+
): Angular.Signal<UseRouteContextResult<TRouter, TFrom, TStrict, TSelected>> {
|
|
26
|
+
return injectMatch({
|
|
27
|
+
...(opts as any),
|
|
28
|
+
select: (match) =>
|
|
29
|
+
opts.select ? opts.select(match.context) : match.context,
|
|
30
|
+
}) as any
|
|
31
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as Angular from '@angular/core'
|
|
2
|
+
import { getRouterInjectionKey } from './routerInjectionToken'
|
|
3
|
+
import type { AnyRouter, RegisteredRouter } from '@benjavicente/router-core'
|
|
4
|
+
|
|
5
|
+
export function injectRouter<
|
|
6
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
7
|
+
>(opts?: { warn?: boolean }): TRouter {
|
|
8
|
+
const router = Angular.inject(getRouterInjectionKey(), { optional: true })
|
|
9
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
10
|
+
if ((opts?.warn ?? true) && !router) {
|
|
11
|
+
console.warn(
|
|
12
|
+
'Warning: injectRouter must be used inside a <router-provider> component!',
|
|
13
|
+
)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return router as any
|
|
17
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { isServer } from '@benjavicente/router-core/isServer'
|
|
2
|
+
import * as Angular from '@angular/core'
|
|
3
|
+
import { deepEqual } from '@benjavicente/router-core'
|
|
4
|
+
import { injectRouter } from './injectRouter'
|
|
5
|
+
import { injectStore } from './injectStore'
|
|
6
|
+
import type {
|
|
7
|
+
AnyRouter,
|
|
8
|
+
RegisteredRouter,
|
|
9
|
+
RouterState,
|
|
10
|
+
} from '@benjavicente/router-core'
|
|
11
|
+
|
|
12
|
+
export type InjectRouterStateOptions<TRouter extends AnyRouter, TSelected> = {
|
|
13
|
+
router?: TRouter
|
|
14
|
+
select?: (state: RouterState<TRouter['routeTree']>) => TSelected
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type InjectRouterStateResult<
|
|
18
|
+
TRouter extends AnyRouter,
|
|
19
|
+
TSelected,
|
|
20
|
+
> = unknown extends TSelected ? RouterState<TRouter['routeTree']> : TSelected
|
|
21
|
+
|
|
22
|
+
export function injectRouterState<
|
|
23
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
24
|
+
TSelected = unknown,
|
|
25
|
+
>(
|
|
26
|
+
opts?: InjectRouterStateOptions<TRouter, TSelected>,
|
|
27
|
+
): Angular.Signal<InjectRouterStateResult<TRouter, TSelected>> {
|
|
28
|
+
const contextRouter = injectRouter({
|
|
29
|
+
warn: opts?.router === undefined,
|
|
30
|
+
})
|
|
31
|
+
const router = opts?.router ?? contextRouter
|
|
32
|
+
const state = injectStore(router.stores.__store, (state) => state)
|
|
33
|
+
|
|
34
|
+
// During SSR we render exactly once and do not need reactivity.
|
|
35
|
+
// Avoid subscribing to the store on the server since the server store
|
|
36
|
+
// implementation does not provide subscribe() semantics.
|
|
37
|
+
const _isServer =
|
|
38
|
+
typeof isServer === 'boolean' ? isServer : router.isServer
|
|
39
|
+
if (_isServer) {
|
|
40
|
+
const state = router.stores.__store.state as RouterState<
|
|
41
|
+
TRouter['routeTree']
|
|
42
|
+
>
|
|
43
|
+
const selected = (
|
|
44
|
+
opts?.select ? opts.select(state) : state
|
|
45
|
+
) as InjectRouterStateResult<TRouter, TSelected>
|
|
46
|
+
return (() => selected) as Angular.Signal<InjectRouterStateResult<TRouter, TSelected>>
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return Angular.computed(() => {
|
|
50
|
+
const result = opts?.select ? opts.select(state()) : state()
|
|
51
|
+
return result as InjectRouterStateResult<TRouter, TSelected>
|
|
52
|
+
}, { equal: deepEqual }) as any;
|
|
53
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { injectMatch } from './injectMatch'
|
|
2
|
+
import type * as Angular from '@angular/core'
|
|
3
|
+
import type {
|
|
4
|
+
AnyRouter,
|
|
5
|
+
RegisteredRouter,
|
|
6
|
+
ResolveUseSearch,
|
|
7
|
+
StrictOrFrom,
|
|
8
|
+
ThrowConstraint,
|
|
9
|
+
ThrowOrOptional,
|
|
10
|
+
UseSearchResult,
|
|
11
|
+
} from '@benjavicente/router-core'
|
|
12
|
+
|
|
13
|
+
export interface InjectSearchBaseOptions<
|
|
14
|
+
TRouter extends AnyRouter,
|
|
15
|
+
TFrom,
|
|
16
|
+
TStrict extends boolean,
|
|
17
|
+
TThrow extends boolean,
|
|
18
|
+
TSelected,
|
|
19
|
+
> {
|
|
20
|
+
select?: (state: ResolveUseSearch<TRouter, TFrom, TStrict>) => TSelected
|
|
21
|
+
shouldThrow?: TThrow
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type InjectSearchOptions<
|
|
25
|
+
TRouter extends AnyRouter,
|
|
26
|
+
TFrom,
|
|
27
|
+
TStrict extends boolean,
|
|
28
|
+
TThrow extends boolean,
|
|
29
|
+
TSelected,
|
|
30
|
+
> = StrictOrFrom<TRouter, TFrom, TStrict> &
|
|
31
|
+
InjectSearchBaseOptions<TRouter, TFrom, TStrict, TThrow, TSelected>
|
|
32
|
+
|
|
33
|
+
export type InjectSearchRoute<out TFrom> = <
|
|
34
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
35
|
+
TSelected = unknown,
|
|
36
|
+
>(
|
|
37
|
+
opts?: InjectSearchBaseOptions<
|
|
38
|
+
TRouter,
|
|
39
|
+
TFrom,
|
|
40
|
+
/* TStrict */ true,
|
|
41
|
+
/* TThrow */ true,
|
|
42
|
+
TSelected
|
|
43
|
+
>,
|
|
44
|
+
) => Angular.Signal<UseSearchResult<TRouter, TFrom, true, TSelected>>
|
|
45
|
+
|
|
46
|
+
export function injectSearch<
|
|
47
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
48
|
+
const TFrom extends string | undefined = undefined,
|
|
49
|
+
TStrict extends boolean = true,
|
|
50
|
+
TThrow extends boolean = true,
|
|
51
|
+
TSelected = unknown,
|
|
52
|
+
>(
|
|
53
|
+
opts: InjectSearchOptions<
|
|
54
|
+
TRouter,
|
|
55
|
+
TFrom,
|
|
56
|
+
TStrict,
|
|
57
|
+
ThrowConstraint<TStrict, TThrow>,
|
|
58
|
+
TSelected
|
|
59
|
+
>,
|
|
60
|
+
): Angular.Signal<
|
|
61
|
+
ThrowOrOptional<UseSearchResult<TRouter, TFrom, TStrict, TSelected>, TThrow>
|
|
62
|
+
> {
|
|
63
|
+
return injectMatch({
|
|
64
|
+
from: opts.from!,
|
|
65
|
+
strict: opts.strict,
|
|
66
|
+
shouldThrow: opts.shouldThrow,
|
|
67
|
+
select: (match: any) => {
|
|
68
|
+
return opts.select ? opts.select(match.search) : match.search
|
|
69
|
+
},
|
|
70
|
+
} as any) as any
|
|
71
|
+
}
|