@real-router/svelte 0.8.0 → 0.9.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.
- package/README.md +10 -0
- package/dist/components/Link.svelte +23 -2
- package/dist/components/Link.svelte.d.ts +7 -0
- package/dist/composables/useIsActiveRoute.svelte.d.ts +1 -1
- package/dist/composables/useIsActiveRoute.svelte.js +7 -5
- package/dist/dom-utils/index.d.ts +1 -1
- package/dist/dom-utils/index.js +1 -1
- package/dist/dom-utils/link-utils.d.ts +18 -2
- package/dist/dom-utils/link-utils.js +50 -3
- package/dist/dom-utils/scroll-restore.js +25 -6
- package/package.json +5 -5
- package/src/components/Link.svelte +23 -2
- package/src/composables/useIsActiveRoute.svelte.ts +12 -4
package/README.md
CHANGED
|
@@ -183,11 +183,21 @@ Navigation link with automatic active state detection. Uses `$derived` for href
|
|
|
183
183
|
| `activeClassName` | `string` | `"active"` | Class added when route is active |
|
|
184
184
|
| `activeStrict` | `boolean` | `false` | Exact match only (no ancestor matching) |
|
|
185
185
|
| `ignoreQueryParams` | `boolean` | `true` | Query params don't affect active state |
|
|
186
|
+
| `hash` | `string` | `undefined` | URL fragment (decoded). Tri-state: undefined preserves, `""` clears, value sets. (#532) |
|
|
186
187
|
| `target` | `string` | `undefined` | Link target (`_blank`, etc.) |
|
|
187
188
|
| `onclick` | `(evt: MouseEvent) => void` | `undefined` | Custom click handler. Runs **before** the navigation logic — call `evt.preventDefault()` to suppress navigation. |
|
|
188
189
|
|
|
189
190
|
All other props are spread onto the `<a>` element.
|
|
190
191
|
|
|
192
|
+
#### `hash` — URL fragment / tab-style UIs
|
|
193
|
+
|
|
194
|
+
```svelte
|
|
195
|
+
<Link routeName="settings" hash="profile">Profile</Link>
|
|
196
|
+
<Link routeName="settings" hash="account">Account</Link>
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Active class is hash-aware — only the matching tab lights up. Live demo: [`examples/web/react/link-hash/`](../../examples/web/react/link-hash/) — behavior is identical across adapters, only template syntax differs. See the [Hash Fragment Support](https://github.com/greydragon888/real-router/wiki/Hash) wiki page for the full surface.
|
|
200
|
+
|
|
191
201
|
### `<Lazy>`
|
|
192
202
|
|
|
193
203
|
Lazy-load route content with a fallback component while loading. Useful for code-splitting and dynamic imports.
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
shouldNavigate,
|
|
7
7
|
buildHref,
|
|
8
8
|
buildActiveClassName,
|
|
9
|
+
navigateWithHash,
|
|
9
10
|
} from "../dom-utils";
|
|
10
11
|
|
|
11
12
|
import type { NavigationOptions, Params } from "@real-router/core";
|
|
@@ -19,6 +20,7 @@
|
|
|
19
20
|
activeClassName = "active",
|
|
20
21
|
activeStrict = false,
|
|
21
22
|
ignoreQueryParams = true,
|
|
23
|
+
hash = undefined,
|
|
22
24
|
target = undefined,
|
|
23
25
|
children = undefined,
|
|
24
26
|
onclick: userOnClick = undefined,
|
|
@@ -31,6 +33,13 @@
|
|
|
31
33
|
activeClassName?: string;
|
|
32
34
|
activeStrict?: boolean;
|
|
33
35
|
ignoreQueryParams?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* URL fragment (decoded form, no leading "#") (#532).
|
|
38
|
+
* - omitted/`undefined` → preserve current fragment on same-route navigation
|
|
39
|
+
* - `""` → clear fragment
|
|
40
|
+
* - non-empty → set fragment
|
|
41
|
+
*/
|
|
42
|
+
hash?: string;
|
|
34
43
|
target?: string;
|
|
35
44
|
children?: Snippet;
|
|
36
45
|
onclick?: (evt: MouseEvent) => void;
|
|
@@ -38,14 +47,24 @@
|
|
|
38
47
|
} = $props();
|
|
39
48
|
|
|
40
49
|
const router = useRouter();
|
|
50
|
+
// Hash-aware active (#532): tab links sharing routeName but differing in
|
|
51
|
+
// hash should only light up the matching variant.
|
|
41
52
|
const activeState = useIsActiveRoute(
|
|
42
53
|
routeName,
|
|
43
54
|
routeParams,
|
|
44
55
|
activeStrict,
|
|
45
56
|
ignoreQueryParams,
|
|
57
|
+
hash,
|
|
46
58
|
);
|
|
47
59
|
|
|
48
|
-
const href = $derived(
|
|
60
|
+
const href = $derived(
|
|
61
|
+
buildHref(
|
|
62
|
+
router,
|
|
63
|
+
routeName,
|
|
64
|
+
routeParams,
|
|
65
|
+
hash !== undefined ? { hash } : undefined,
|
|
66
|
+
),
|
|
67
|
+
);
|
|
49
68
|
|
|
50
69
|
const finalClassName = $derived(
|
|
51
70
|
buildActiveClassName(activeState.current, activeClassName, className),
|
|
@@ -65,7 +84,9 @@
|
|
|
65
84
|
}
|
|
66
85
|
|
|
67
86
|
evt.preventDefault();
|
|
68
|
-
router
|
|
87
|
+
navigateWithHash(router, routeName, routeParams, hash, routeOptions).catch(
|
|
88
|
+
NOOP,
|
|
89
|
+
);
|
|
69
90
|
}
|
|
70
91
|
</script>
|
|
71
92
|
|
|
@@ -8,6 +8,13 @@ type $$ComponentProps = {
|
|
|
8
8
|
activeClassName?: string;
|
|
9
9
|
activeStrict?: boolean;
|
|
10
10
|
ignoreQueryParams?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* URL fragment (decoded form, no leading "#") (#532).
|
|
13
|
+
* - omitted/`undefined` → preserve current fragment on same-route navigation
|
|
14
|
+
* - `""` → clear fragment
|
|
15
|
+
* - non-empty → set fragment
|
|
16
|
+
*/
|
|
17
|
+
hash?: string;
|
|
11
18
|
target?: string;
|
|
12
19
|
children?: Snippet;
|
|
13
20
|
onclick?: (evt: MouseEvent) => void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { Params } from "@real-router/core";
|
|
2
|
-
export declare function useIsActiveRoute(routeName: string, params: Params | undefined, strict: boolean, ignoreQueryParams: boolean): {
|
|
2
|
+
export declare function useIsActiveRoute(routeName: string, params: Params | undefined, strict: boolean, ignoreQueryParams: boolean, hash?: string): {
|
|
3
3
|
readonly current: boolean;
|
|
4
4
|
};
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { createActiveRouteSource } from "@real-router/sources";
|
|
2
2
|
import { createReactiveSource } from "../createReactiveSource.svelte";
|
|
3
3
|
import { useRouter } from "./useRouter.svelte";
|
|
4
|
-
export function useIsActiveRoute(routeName, params, strict, ignoreQueryParams) {
|
|
4
|
+
export function useIsActiveRoute(routeName, params, strict, ignoreQueryParams, hash) {
|
|
5
5
|
const router = useRouter();
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
// The `hash` argument (#532) participates in the cache key when defined.
|
|
7
|
+
// exactOptionalPropertyTypes forbids `{ hash: undefined }` literally — we
|
|
8
|
+
// conditionally include the key only when a value is provided.
|
|
9
|
+
const source = createActiveRouteSource(router, routeName, params, hash === undefined
|
|
10
|
+
? { strict, ignoreQueryParams }
|
|
11
|
+
: { strict, ignoreQueryParams, hash });
|
|
10
12
|
return createReactiveSource(source);
|
|
11
13
|
}
|
|
@@ -2,7 +2,7 @@ export { createDirectionTracker } from "./direction-tracker.js";
|
|
|
2
2
|
export { createRouteAnnouncer } from "./route-announcer.js";
|
|
3
3
|
export { createScrollRestoration } from "./scroll-restore.js";
|
|
4
4
|
export { createViewTransitions } from "./view-transitions.js";
|
|
5
|
-
export { shouldNavigate, buildHref, buildActiveClassName, shallowEqual, applyLinkA11y, } from "./link-utils.js";
|
|
5
|
+
export { shouldNavigate, buildHref, buildActiveClassName, navigateWithHash, shallowEqual, applyLinkA11y, } from "./link-utils.js";
|
|
6
6
|
export type { RouteAnnouncerOptions } from "./route-announcer.js";
|
|
7
7
|
export type { ScrollRestorationOptions, ScrollRestorationMode, } from "./scroll-restore.js";
|
|
8
8
|
export type { DirectionTracker } from "./direction-tracker.js";
|
package/dist/dom-utils/index.js
CHANGED
|
@@ -2,4 +2,4 @@ export { createDirectionTracker } from "./direction-tracker.js";
|
|
|
2
2
|
export { createRouteAnnouncer } from "./route-announcer.js";
|
|
3
3
|
export { createScrollRestoration } from "./scroll-restore.js";
|
|
4
4
|
export { createViewTransitions } from "./view-transitions.js";
|
|
5
|
-
export { shouldNavigate, buildHref, buildActiveClassName, shallowEqual, applyLinkA11y, } from "./link-utils.js";
|
|
5
|
+
export { shouldNavigate, buildHref, buildActiveClassName, navigateWithHash, shallowEqual, applyLinkA11y, } from "./link-utils.js";
|
|
@@ -1,6 +1,22 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { NavigationOptions, Params, Router, State } from "@real-router/core";
|
|
2
2
|
export declare function shouldNavigate(evt: MouseEvent): boolean;
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Builds an href for a `<Link>` element.
|
|
5
|
+
*
|
|
6
|
+
* - Prefers the URL plugin's `buildUrl` (browser-plugin, navigation-plugin,
|
|
7
|
+
* hash-plugin) when present.
|
|
8
|
+
* - Falls back to `router.buildPath` for runtimes without a URL plugin
|
|
9
|
+
* (memory-plugin, console UIs, NativeScript). In that fallback the hash
|
|
10
|
+
* is appended manually so the rendered href is still correct.
|
|
11
|
+
* - The optional 4th argument is an options object so the contract stays
|
|
12
|
+
* extensible. The `hash` option is a decoded fragment without leading "#";
|
|
13
|
+
* `<Link hash="#section">` is accepted defensively (leading "#" stripped).
|
|
14
|
+
* Frozen API: previous 3-arg call sites continue to work unchanged.
|
|
15
|
+
*/
|
|
16
|
+
export declare function buildHref(router: Router, routeName: string, routeParams: Params, options?: {
|
|
17
|
+
hash?: string;
|
|
18
|
+
}): string | undefined;
|
|
19
|
+
export declare function navigateWithHash(router: Router, routeName: string, routeParams: Params, hash: string | undefined, extraOptions?: NavigationOptions): Promise<State>;
|
|
4
20
|
export declare function buildActiveClassName(isActive: boolean, activeClassName: string | undefined, baseClassName: string | undefined): string | undefined;
|
|
5
21
|
export declare function shallowEqual(prev: object | undefined, next: object | undefined): boolean;
|
|
6
22
|
export declare function applyLinkA11y(element: HTMLElement | null | undefined): void;
|
|
@@ -5,22 +5,69 @@ export function shouldNavigate(evt) {
|
|
|
5
5
|
!evt.ctrlKey &&
|
|
6
6
|
!evt.shiftKey);
|
|
7
7
|
}
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* RFC 3986 fragment encoding: preserve sub-delims (`&`, `=`, `?`, `:`),
|
|
10
|
+
* encode space, `%`, control chars, non-ASCII via encodeURI; defensively
|
|
11
|
+
* escape `#` (encodeURI does not). Mirrors `encodeHashFragment` in
|
|
12
|
+
* `shared/browser-env/url-context.ts` — duplicated here because the
|
|
13
|
+
* shared/dom-utils symlink graph does not reach shared/browser-env.
|
|
14
|
+
*/
|
|
15
|
+
function encodeFragmentInline(decoded) {
|
|
16
|
+
return encodeURI(decoded).replaceAll("#", "%23");
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Builds an href for a `<Link>` element.
|
|
20
|
+
*
|
|
21
|
+
* - Prefers the URL plugin's `buildUrl` (browser-plugin, navigation-plugin,
|
|
22
|
+
* hash-plugin) when present.
|
|
23
|
+
* - Falls back to `router.buildPath` for runtimes without a URL plugin
|
|
24
|
+
* (memory-plugin, console UIs, NativeScript). In that fallback the hash
|
|
25
|
+
* is appended manually so the rendered href is still correct.
|
|
26
|
+
* - The optional 4th argument is an options object so the contract stays
|
|
27
|
+
* extensible. The `hash` option is a decoded fragment without leading "#";
|
|
28
|
+
* `<Link hash="#section">` is accepted defensively (leading "#" stripped).
|
|
29
|
+
* Frozen API: previous 3-arg call sites continue to work unchanged.
|
|
30
|
+
*/
|
|
31
|
+
export function buildHref(router, routeName, routeParams, options) {
|
|
9
32
|
try {
|
|
33
|
+
const rawHash = options?.hash;
|
|
34
|
+
let normHash;
|
|
35
|
+
if (rawHash !== undefined) {
|
|
36
|
+
normHash = rawHash.startsWith("#") ? rawHash.slice(1) : rawHash;
|
|
37
|
+
}
|
|
10
38
|
const buildUrl = router.buildUrl;
|
|
11
39
|
if (buildUrl) {
|
|
12
|
-
const url = buildUrl(routeName, routeParams);
|
|
40
|
+
const url = buildUrl(routeName, routeParams, normHash === undefined ? undefined : { hash: normHash });
|
|
13
41
|
if (url !== undefined) {
|
|
14
42
|
return url;
|
|
15
43
|
}
|
|
16
44
|
}
|
|
17
|
-
|
|
45
|
+
const path = router.buildPath(routeName, routeParams);
|
|
46
|
+
return normHash ? `${path}#${encodeFragmentInline(normHash)}` : path;
|
|
18
47
|
}
|
|
19
48
|
catch {
|
|
20
49
|
console.error(`[real-router] Route "${routeName}" is not defined. The element will render without an href attribute.`);
|
|
21
50
|
return undefined;
|
|
22
51
|
}
|
|
23
52
|
}
|
|
53
|
+
export function navigateWithHash(router, routeName, routeParams, hash, extraOptions) {
|
|
54
|
+
const opts = { ...extraOptions };
|
|
55
|
+
if (hash !== undefined) {
|
|
56
|
+
opts.hash = hash;
|
|
57
|
+
}
|
|
58
|
+
const current = router.getState();
|
|
59
|
+
if (current?.name === routeName &&
|
|
60
|
+
shallowEqual(current.params, routeParams)) {
|
|
61
|
+
const currentHash = current.context?.url?.hash ??
|
|
62
|
+
"";
|
|
63
|
+
const newHash = hash ?? currentHash;
|
|
64
|
+
if (currentHash !== newHash) {
|
|
65
|
+
opts.force = true;
|
|
66
|
+
opts.hashChange = true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return router.navigate(routeName, routeParams, opts);
|
|
70
|
+
}
|
|
24
71
|
function parseTokens(value) {
|
|
25
72
|
return value ? (value.match(/\S+/g) ?? []) : [];
|
|
26
73
|
}
|
|
@@ -40,12 +40,31 @@ export function createScrollRestoration(router, options) {
|
|
|
40
40
|
globalThis.scrollTo(0, top);
|
|
41
41
|
}
|
|
42
42
|
};
|
|
43
|
-
const scrollToHashOrTop = () => {
|
|
43
|
+
const scrollToHashOrTop = (route) => {
|
|
44
|
+
// URL plugin path (#532): `state.context.url.hash` is the source of truth
|
|
45
|
+
// when one of the URL plugins (browser-plugin / navigation-plugin) is
|
|
46
|
+
// installed. The value is already DECODED — feeding it through
|
|
47
|
+
// `decodeURIComponent` again would throw on a bare `%`.
|
|
48
|
+
const ctxHash = route.context
|
|
49
|
+
?.url?.hash;
|
|
50
|
+
if (ctxHash !== undefined) {
|
|
51
|
+
if (anchorEnabled && ctxHash.length > 0) {
|
|
52
|
+
// eslint-disable-next-line unicorn/prefer-query-selector -- ids may contain CSS-unsafe chars
|
|
53
|
+
const element = document.getElementById(ctxHash);
|
|
54
|
+
if (element) {
|
|
55
|
+
element.scrollIntoView();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
writePos(0);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
// Fallback path: no URL plugin, read the DOM. `location.hash` is
|
|
63
|
+
// percent-encoded; ids in the DOM are the raw string, so decode for the
|
|
64
|
+
// match. Fall back to the raw slice if the hash contains a malformed
|
|
65
|
+
// escape sequence (decodeURIComponent throws on those).
|
|
44
66
|
const hash = globalThis.location.hash;
|
|
45
67
|
if (anchorEnabled && hash.length > 1) {
|
|
46
|
-
// location.hash is percent-encoded; ids in the DOM are the raw string.
|
|
47
|
-
// Decode for the match. Fall back to the raw slice if the hash contains
|
|
48
|
-
// a malformed escape sequence (decodeURIComponent throws on those).
|
|
49
68
|
let id;
|
|
50
69
|
try {
|
|
51
70
|
id = decodeURIComponent(hash.slice(1));
|
|
@@ -79,7 +98,7 @@ export function createScrollRestoration(router, options) {
|
|
|
79
98
|
return;
|
|
80
99
|
}
|
|
81
100
|
if (mode === "top" || !nav) {
|
|
82
|
-
scrollToHashOrTop();
|
|
101
|
+
scrollToHashOrTop(route);
|
|
83
102
|
return;
|
|
84
103
|
}
|
|
85
104
|
if (nav.navigationType === "replace") {
|
|
@@ -91,7 +110,7 @@ export function createScrollRestoration(router, options) {
|
|
|
91
110
|
writePos(loadStore()[keyOf(route)] ?? 0);
|
|
92
111
|
return;
|
|
93
112
|
}
|
|
94
|
-
scrollToHashOrTop();
|
|
113
|
+
scrollToHashOrTop(route);
|
|
95
114
|
});
|
|
96
115
|
});
|
|
97
116
|
const onPageHide = () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@real-router/svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Svelte 5 integration for Real-Router",
|
|
6
6
|
"svelte": "./dist/index.js",
|
|
@@ -44,9 +44,9 @@
|
|
|
44
44
|
"license": "MIT",
|
|
45
45
|
"sideEffects": false,
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@real-router/core": "^0.
|
|
48
|
-
"@real-router/route-utils": "^0.2.
|
|
49
|
-
"@real-router/sources": "^0.
|
|
47
|
+
"@real-router/core": "^0.51.0",
|
|
48
|
+
"@real-router/route-utils": "^0.2.2",
|
|
49
|
+
"@real-router/sources": "^0.8.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@sveltejs/package": "2.5.7",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"svelte": "5.54.0",
|
|
59
59
|
"svelte-check": "4.4.5",
|
|
60
60
|
"svelte-eslint-parser": "1.6.0",
|
|
61
|
-
"@real-router/browser-plugin": "^0.
|
|
61
|
+
"@real-router/browser-plugin": "^0.17.0"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
64
|
"svelte": ">=5.7.0"
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
shouldNavigate,
|
|
7
7
|
buildHref,
|
|
8
8
|
buildActiveClassName,
|
|
9
|
+
navigateWithHash,
|
|
9
10
|
} from "../dom-utils";
|
|
10
11
|
|
|
11
12
|
import type { NavigationOptions, Params } from "@real-router/core";
|
|
@@ -19,6 +20,7 @@
|
|
|
19
20
|
activeClassName = "active",
|
|
20
21
|
activeStrict = false,
|
|
21
22
|
ignoreQueryParams = true,
|
|
23
|
+
hash = undefined,
|
|
22
24
|
target = undefined,
|
|
23
25
|
children = undefined,
|
|
24
26
|
onclick: userOnClick = undefined,
|
|
@@ -31,6 +33,13 @@
|
|
|
31
33
|
activeClassName?: string;
|
|
32
34
|
activeStrict?: boolean;
|
|
33
35
|
ignoreQueryParams?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* URL fragment (decoded form, no leading "#") (#532).
|
|
38
|
+
* - omitted/`undefined` → preserve current fragment on same-route navigation
|
|
39
|
+
* - `""` → clear fragment
|
|
40
|
+
* - non-empty → set fragment
|
|
41
|
+
*/
|
|
42
|
+
hash?: string;
|
|
34
43
|
target?: string;
|
|
35
44
|
children?: Snippet;
|
|
36
45
|
onclick?: (evt: MouseEvent) => void;
|
|
@@ -38,14 +47,24 @@
|
|
|
38
47
|
} = $props();
|
|
39
48
|
|
|
40
49
|
const router = useRouter();
|
|
50
|
+
// Hash-aware active (#532): tab links sharing routeName but differing in
|
|
51
|
+
// hash should only light up the matching variant.
|
|
41
52
|
const activeState = useIsActiveRoute(
|
|
42
53
|
routeName,
|
|
43
54
|
routeParams,
|
|
44
55
|
activeStrict,
|
|
45
56
|
ignoreQueryParams,
|
|
57
|
+
hash,
|
|
46
58
|
);
|
|
47
59
|
|
|
48
|
-
const href = $derived(
|
|
60
|
+
const href = $derived(
|
|
61
|
+
buildHref(
|
|
62
|
+
router,
|
|
63
|
+
routeName,
|
|
64
|
+
routeParams,
|
|
65
|
+
hash !== undefined ? { hash } : undefined,
|
|
66
|
+
),
|
|
67
|
+
);
|
|
49
68
|
|
|
50
69
|
const finalClassName = $derived(
|
|
51
70
|
buildActiveClassName(activeState.current, activeClassName, className),
|
|
@@ -65,7 +84,9 @@
|
|
|
65
84
|
}
|
|
66
85
|
|
|
67
86
|
evt.preventDefault();
|
|
68
|
-
router
|
|
87
|
+
navigateWithHash(router, routeName, routeParams, hash, routeOptions).catch(
|
|
88
|
+
NOOP,
|
|
89
|
+
);
|
|
69
90
|
}
|
|
70
91
|
</script>
|
|
71
92
|
|
|
@@ -10,13 +10,21 @@ export function useIsActiveRoute(
|
|
|
10
10
|
params: Params | undefined,
|
|
11
11
|
strict: boolean,
|
|
12
12
|
ignoreQueryParams: boolean,
|
|
13
|
+
hash?: string,
|
|
13
14
|
): { readonly current: boolean } {
|
|
14
15
|
const router = useRouter();
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
// The `hash` argument (#532) participates in the cache key when defined.
|
|
18
|
+
// exactOptionalPropertyTypes forbids `{ hash: undefined }` literally — we
|
|
19
|
+
// conditionally include the key only when a value is provided.
|
|
20
|
+
const source = createActiveRouteSource(
|
|
21
|
+
router,
|
|
22
|
+
routeName,
|
|
23
|
+
params,
|
|
24
|
+
hash === undefined
|
|
25
|
+
? { strict, ignoreQueryParams }
|
|
26
|
+
: { strict, ignoreQueryParams, hash },
|
|
27
|
+
);
|
|
20
28
|
|
|
21
29
|
return createReactiveSource(source);
|
|
22
30
|
}
|