sv-router 0.16.0 → 0.16.2
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 +9 -10
- package/package.json +27 -27
- package/src/Router.svelte +8 -3
- package/src/create-router.svelte.js +2 -0
- package/src/helpers/utils.js +2 -2
- package/src/index.d.ts +1 -0
- package/src/search-params.svelte.js +8 -2
package/README.md
CHANGED
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
# sv-router
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/sv-router)
|
|
8
|
-
|
|
8
|
+

|
|
9
|
+

|
|
9
10
|
[](https://codecov.io/github/colinlienard/sv-router)
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
Flexible, ergonomic, and complete Svelte 5 router.
|
|
12
13
|
|
|
13
14
|
[Documentation](https://sv-router.vercel.app/) • [Getting Started](https://sv-router.vercel.app/guide/getting-started) • [Reference](https://sv-router.vercel.app/reference)
|
|
14
15
|
|
|
@@ -18,16 +19,14 @@ A feature-rich yet intuitive routing library for Svelte single-page apps.
|
|
|
18
19
|
|
|
19
20
|
## Features
|
|
20
21
|
|
|
21
|
-
- 🔒 **
|
|
22
|
-
-
|
|
23
|
-
-
|
|
22
|
+
- 🔒 **Type-safe navigation**: Catch broken links before you ship.
|
|
23
|
+
- 🗂️ **File-based routing (optional)**: DX of a meta-framework-like approach.
|
|
24
|
+
- 🪶 **Lightweight**: < 5kB gzipped.
|
|
25
|
+
- ⚡ **Performance**: Built-in code splitting and preloading.
|
|
24
26
|
- 🔍 **Reactive search params**: For simpler state management in the URL.
|
|
27
|
+
- 🌿 **Nested routes**: Share layouts across pages.
|
|
25
28
|
- 🛡️ **Hooks**: For navigation guards, data loading, or analytics tracking.
|
|
26
|
-
-
|
|
27
|
-
- 🧩 **Familiar API**: Follows established conventions from popular meta frameworks.
|
|
28
|
-
- 🪶 **Lightweight**: Minimal impact on your bundle size.
|
|
29
|
-
- 🚀 **Made for Svelte 5**: True Svelte 5 implementation with the latest features.
|
|
30
|
-
- #️⃣ **Hash-based routing**: Hash-based routing enables usage in local environments.
|
|
29
|
+
- #️⃣ **Hash-based routing**: Works inside Electron/Tauri.
|
|
31
30
|
|
|
32
31
|
## Getting Started
|
|
33
32
|
|
package/package.json
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sv-router",
|
|
3
|
-
"version": "0.16.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.16.2",
|
|
4
|
+
"description": "Type-safe routing for Svelte SPAs",
|
|
5
5
|
"keywords": [
|
|
6
|
-
"svelte",
|
|
7
6
|
"router",
|
|
8
|
-
"spa"
|
|
7
|
+
"spa",
|
|
8
|
+
"svelte"
|
|
9
9
|
],
|
|
10
10
|
"homepage": "https://github.com/colinlienard/sv-router",
|
|
11
11
|
"bugs": {
|
|
12
12
|
"url": "https://github.com/colinlienard/sv-router/issues"
|
|
13
13
|
},
|
|
14
|
+
"license": "MIT",
|
|
14
15
|
"repository": {
|
|
15
16
|
"type": "git",
|
|
16
17
|
"url": "git+https://github.com/colinlienard/sv-router.git"
|
|
17
18
|
},
|
|
18
|
-
"
|
|
19
|
+
"files": [
|
|
20
|
+
"src"
|
|
21
|
+
],
|
|
19
22
|
"type": "module",
|
|
20
23
|
"exports": {
|
|
21
24
|
".": {
|
|
@@ -28,38 +31,32 @@
|
|
|
28
31
|
"types": "./src/vite-plugin/index.d.ts"
|
|
29
32
|
}
|
|
30
33
|
},
|
|
31
|
-
"bin": "./src/cli/index.js",
|
|
32
|
-
"files": [
|
|
33
|
-
"src"
|
|
34
|
-
],
|
|
35
34
|
"dependencies": {
|
|
36
35
|
"esm-env": "^1.2.2"
|
|
37
36
|
},
|
|
38
37
|
"devDependencies": {
|
|
39
|
-
"@changesets/cli": "^2.
|
|
38
|
+
"@changesets/cli": "^2.31.0",
|
|
40
39
|
"@eslint/js": "^10.0.1",
|
|
41
|
-
"@sveltejs/vite-plugin-svelte": "^7.
|
|
40
|
+
"@sveltejs/vite-plugin-svelte": "^7.1.2",
|
|
42
41
|
"@testing-library/jest-dom": "^6.9.1",
|
|
43
42
|
"@testing-library/svelte": "^5.3.1",
|
|
44
43
|
"@testing-library/user-event": "^14.6.1",
|
|
45
|
-
"@types/node": "^24.12.
|
|
46
|
-
"@vitest/coverage-v8": "^4.1.
|
|
47
|
-
"eslint": "^10.0
|
|
44
|
+
"@types/node": "^24.12.3",
|
|
45
|
+
"@vitest/coverage-v8": "^4.1.5",
|
|
46
|
+
"eslint": "^10.3.0",
|
|
48
47
|
"eslint-config-prettier": "^10.1.8",
|
|
49
48
|
"eslint-plugin-simple-import-sort": "^13.0.0",
|
|
50
|
-
"eslint-plugin-svelte": "^3.
|
|
49
|
+
"eslint-plugin-svelte": "^3.17.1",
|
|
51
50
|
"eslint-plugin-unicorn": "^64.0.0",
|
|
52
|
-
"globals": "^17.
|
|
53
|
-
"happy-dom": "^20.
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"prettier-plugin-svelte": "^3.5.1",
|
|
57
|
-
"svelte-check": "^4.4.5",
|
|
51
|
+
"globals": "^17.6.0",
|
|
52
|
+
"happy-dom": "^20.9.0",
|
|
53
|
+
"oxfmt": "^0.49.0",
|
|
54
|
+
"svelte-check": "^4.4.8",
|
|
58
55
|
"type-testing": "^0.2.0",
|
|
59
|
-
"typescript": "^6.0.
|
|
60
|
-
"typescript-eslint": "^8.
|
|
61
|
-
"vite": "^8.0.
|
|
62
|
-
"vitest": "^4.1.
|
|
56
|
+
"typescript": "^6.0.3",
|
|
57
|
+
"typescript-eslint": "^8.59.2",
|
|
58
|
+
"vite": "^8.0.11",
|
|
59
|
+
"vitest": "^4.1.5"
|
|
63
60
|
},
|
|
64
61
|
"peerDependencies": {
|
|
65
62
|
"svelte": "^5"
|
|
@@ -75,8 +72,11 @@
|
|
|
75
72
|
"check": "svelte-check && pnpm -r check",
|
|
76
73
|
"lint": "eslint . --max-warnings 0",
|
|
77
74
|
"lint:fix": "eslint . --fix",
|
|
78
|
-
"format": "
|
|
79
|
-
"format:fix": "
|
|
75
|
+
"format": "oxfmt --check",
|
|
76
|
+
"format:fix": "oxfmt",
|
|
80
77
|
"changeset": "changeset"
|
|
78
|
+
},
|
|
79
|
+
"bin": {
|
|
80
|
+
"sv-router": "./src/cli/index.js"
|
|
81
81
|
}
|
|
82
82
|
}
|
package/src/Router.svelte
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script>
|
|
2
|
+
import { untrack } from 'svelte';
|
|
2
3
|
import { on } from 'svelte/events';
|
|
3
4
|
import {
|
|
4
5
|
componentTree,
|
|
@@ -7,15 +8,19 @@
|
|
|
7
8
|
onGlobalClick,
|
|
8
9
|
onNavigate,
|
|
9
10
|
} from './create-router.svelte.js';
|
|
11
|
+
import { getUserState } from './helpers/utils.js';
|
|
10
12
|
import RecursiveComponentTree from './RecursiveComponentTree.svelte';
|
|
11
13
|
|
|
12
14
|
/** @type {{ base?: string }} */
|
|
13
15
|
let { base: basename } = $props();
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
init(basename);
|
|
17
|
+
init(untrack(() => basename));
|
|
17
18
|
|
|
18
|
-
onNavigate(
|
|
19
|
+
onNavigate(undefined, {
|
|
20
|
+
search: location.search,
|
|
21
|
+
hash: location.hash,
|
|
22
|
+
state: getUserState(history.state),
|
|
23
|
+
});
|
|
19
24
|
|
|
20
25
|
$effect(() => {
|
|
21
26
|
const cleanup = [
|
|
@@ -345,6 +345,8 @@ export function onGlobalClick(event) {
|
|
|
345
345
|
const path = base.name === '#' ? url.hash : url.pathname;
|
|
346
346
|
const hash = base.name === '#' ? undefined : url.hash;
|
|
347
347
|
|
|
348
|
+
if (base.name && base.name !== '#' && !path.startsWith(base.name)) return;
|
|
349
|
+
|
|
348
350
|
event.preventDefault();
|
|
349
351
|
const { replace, state, scrollToTop, viewTransition } = anchor.dataset;
|
|
350
352
|
|
package/src/helpers/utils.js
CHANGED
|
@@ -68,7 +68,7 @@ function resolveRouteComponent(input) {
|
|
|
68
68
|
|
|
69
69
|
/**
|
|
70
70
|
* @param {unknown} input
|
|
71
|
-
* @returns {input is import(
|
|
71
|
+
* @returns {input is import("../index.d.ts").LazyRouteComponent}
|
|
72
72
|
*/
|
|
73
73
|
export function isLazyImport(input) {
|
|
74
74
|
return (
|
|
@@ -104,7 +104,7 @@ export function stripBase(pathname) {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
/** @param {any} state */
|
|
107
|
-
function getUserState(state) {
|
|
107
|
+
export function getUserState(state) {
|
|
108
108
|
if (state && '_userState' in state) {
|
|
109
109
|
return state._userState;
|
|
110
110
|
}
|
package/src/index.d.ts
CHANGED
|
@@ -316,6 +316,7 @@ export type SearchParams = Omit<
|
|
|
316
316
|
getAll(name: string): (string | number | boolean)[];
|
|
317
317
|
set(name: string, value: string | number | boolean, options?: { replace?: boolean }): void;
|
|
318
318
|
sort(options?: { replace?: boolean }): void;
|
|
319
|
+
toURLSearchParams(): URLSearchParams;
|
|
319
320
|
values(): (string | number | boolean)[];
|
|
320
321
|
};
|
|
321
322
|
|
|
@@ -47,6 +47,9 @@ const shell = {
|
|
|
47
47
|
values() {
|
|
48
48
|
return [...searchParams.values()].map(parseSearchValue);
|
|
49
49
|
},
|
|
50
|
+
toURLSearchParams() {
|
|
51
|
+
return new URLSearchParams(searchParams);
|
|
52
|
+
},
|
|
50
53
|
get size() {
|
|
51
54
|
return searchParams.size;
|
|
52
55
|
},
|
|
@@ -63,8 +66,11 @@ export function syncSearchParams(search) {
|
|
|
63
66
|
return;
|
|
64
67
|
}
|
|
65
68
|
const newSearch = new URLSearchParams(search);
|
|
66
|
-
for (const
|
|
67
|
-
searchParams.
|
|
69
|
+
for (const key of newSearch.keys()) {
|
|
70
|
+
searchParams.delete(key);
|
|
71
|
+
for (const value of newSearch.getAll(key)) {
|
|
72
|
+
searchParams.append(key, value);
|
|
73
|
+
}
|
|
68
74
|
}
|
|
69
75
|
// eslint-disable-next-line unicorn/no-useless-spread
|
|
70
76
|
for (const key of [...searchParams.keys()]) {
|