From db46f52f069344fb989b4e088c82dbfc8df79f04 Mon Sep 17 00:00:00 2001 From: richardjelinek-fastest Date: Thu, 3 Jul 2025 15:35:48 +0200 Subject: [PATCH 1/3] fix: pass parameters into onNavigate in Router.svelte --- .changeset/hot-pugs-worry.md | 5 +++++ src/create-router.svelte.js | 8 +++++--- src/index.d.ts | 4 +++- 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 .changeset/hot-pugs-worry.md diff --git a/.changeset/hot-pugs-worry.md b/.changeset/hot-pugs-worry.md new file mode 100644 index 0000000..c8e43fc --- /dev/null +++ b/.changeset/hot-pugs-worry.md @@ -0,0 +1,5 @@ +--- +'sv-router': patch +--- + +pass initial page pathname, search, hash to onNavigate, correctly handle cancellation of navigations, return Error in navigate diff --git a/src/create-router.svelte.js b/src/create-router.svelte.js index 563b557..50692b7 100644 --- a/src/create-router.svelte.js +++ b/src/create-router.svelte.js @@ -114,11 +114,12 @@ export function createRouter(r) { * params?: Record; * search?: import('./index.d.ts').Search; * }} options + * @returns Promise */ function navigate(path, options = {}) { if (typeof path === 'number') { globalThis.history.go(path); - return; + return new Error(`Navigating to history entry: ${path}`); } path = constructPath(path, options.params); @@ -128,10 +129,11 @@ function navigate(path, options = {}) { options.hash = '#' + options.hash; } onNavigate(path, options); + return new Error(`Navigating to: ${path}${options?.search ?? ''}${options?.hash ?? ''}`); } /** - * @param {string} [path] + * @param {string} path * @param {import('./index.d.ts').NavigateOptions} options */ export async function onNavigate(path, options = {}) { @@ -253,7 +255,7 @@ export function onGlobalClick(event) { event.preventDefault(); const { replace, state, scrollToTop, viewTransition } = anchor.dataset; - onNavigate(path, { + void onNavigate(path, { replace: replace === '' || replace === 'true', search: url.search, state, diff --git a/src/index.d.ts b/src/index.d.ts index e5b540e..04e28da 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -139,8 +139,10 @@ export type RouterApi = { * * @param route The route to navigate to. * @param options The navigation options. + * + * Returns an Error for use with `throw navigate(...)` inside hooks. */ - navigate>(...args: NavigateArgs): void; + navigate>(...args: NavigateArgs): Error; /** * Will return `true` if the given path is active. From 72eb556cfc890bf5772c3cb8d5ebea42aa35fab2 Mon Sep 17 00:00:00 2001 From: richardjelinek-fastest Date: Wed, 9 Jul 2025 16:07:45 +0200 Subject: [PATCH 2/3] chore: use custom error class for navigation --- src/create-router.svelte.js | 5 +++-- src/index.d.ts | 4 ++++ src/index.js | 1 + src/navigation.js | 9 +++++++++ 4 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 src/navigation.js diff --git a/src/create-router.svelte.js b/src/create-router.svelte.js index 50692b7..6bb2ac2 100644 --- a/src/create-router.svelte.js +++ b/src/create-router.svelte.js @@ -2,6 +2,7 @@ import { BROWSER, DEV } from 'esm-env'; import { isActive } from './helpers/is-active.js'; import { matchRoute } from './helpers/match-route.js'; import { preload, preloadOnHover } from './helpers/preload.js'; +import { Navigation } from './navigation.js'; import { constructPath, constructUrl, @@ -119,7 +120,7 @@ export function createRouter(r) { function navigate(path, options = {}) { if (typeof path === 'number') { globalThis.history.go(path); - return new Error(`Navigating to history entry: ${path}`); + return new Navigation(`History entry: ${path}`); } path = constructPath(path, options.params); @@ -129,7 +130,7 @@ function navigate(path, options = {}) { options.hash = '#' + options.hash; } onNavigate(path, options); - return new Error(`Navigating to: ${path}${options?.search ?? ''}${options?.hash ?? ''}`); + return new Navigation(`${path}${options?.search ?? ''}${options?.hash ?? ''}`); } /** diff --git a/src/index.d.ts b/src/index.d.ts index 04e28da..6f8c8c1 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -106,6 +106,10 @@ export type IsActiveLink = Action< // eslint-disable-next-line @typescript-eslint/no-empty-object-type export interface RouteMeta {} +export class Navigation extends Error { + constructor(target: string); +} + export type RouterApi = { /** * Construct a path while ensuring type safety. diff --git a/src/index.js b/src/index.js index 15091c0..802c774 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,6 @@ export { isActiveLink } from './actions.svelte.js'; export { createRouter } from './create-router.svelte.js'; export { serializeSearch } from './helpers/utils.js'; +export { Navigation } from './navigation.js'; export { default as Router } from './Router.svelte'; export { searchParams } from './search-params.svelte.js'; diff --git a/src/navigation.js b/src/navigation.js new file mode 100644 index 0000000..ad2719a --- /dev/null +++ b/src/navigation.js @@ -0,0 +1,9 @@ +export class Navigation extends Error { + constructor( + /** @type {string} target */ + target, + ) { + super(`Navigating to: ${target}`); + this.name = 'Redirect'; + } +} From f0792b79ae77bbc6f637cace6fa8b0cad1dcedde Mon Sep 17 00:00:00 2001 From: richardjelinek-fastest Date: Tue, 19 Aug 2025 21:27:48 +0200 Subject: [PATCH 3/3] fix: introduce the missing navigation cancellation fix --- .changeset/hot-pugs-worry.md | 2 +- src/create-router.svelte.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.changeset/hot-pugs-worry.md b/.changeset/hot-pugs-worry.md index c8e43fc..bc6cf26 100644 --- a/.changeset/hot-pugs-worry.md +++ b/.changeset/hot-pugs-worry.md @@ -2,4 +2,4 @@ 'sv-router': patch --- -pass initial page pathname, search, hash to onNavigate, correctly handle cancellation of navigations, return Error in navigate +correctly handle cancellation of navigations, return Error in navigate diff --git a/src/create-router.svelte.js b/src/create-router.svelte.js index 6bb2ac2..5778b41 100644 --- a/src/create-router.svelte.js +++ b/src/create-router.svelte.js @@ -2,7 +2,6 @@ import { BROWSER, DEV } from 'esm-env'; import { isActive } from './helpers/is-active.js'; import { matchRoute } from './helpers/match-route.js'; import { preload, preloadOnHover } from './helpers/preload.js'; -import { Navigation } from './navigation.js'; import { constructPath, constructUrl, @@ -13,6 +12,7 @@ import { stripBase, updatedLocation, } from './helpers/utils.js'; +import { Navigation } from './navigation.js'; import { syncSearchParams } from './search-params.svelte.js'; /** @type {import('./index.d.ts').Routes} */ @@ -134,7 +134,7 @@ function navigate(path, options = {}) { } /** - * @param {string} path + * @param {string} [path] * @param {import('./index.d.ts').NavigateOptions} options */ export async function onNavigate(path, options = {}) { @@ -145,7 +145,7 @@ export async function onNavigate(path, options = {}) { navigationIndex++; const currentNavigationIndex = navigationIndex; - let matchPath = getMatchPath(path); + const matchPath = getMatchPath(path); const { match, layouts, hooks, meta: newMeta, params: newParams } = matchRoute(matchPath, routes); const search = parseSearch(options.search); @@ -179,7 +179,7 @@ export async function onNavigate(path, options = {}) { } if ( navigationIndex !== currentNavigationIndex || - (fromBeforeLoadHook && pendingNavigationIndex + 1 !== currentNavigationIndex) + (fromBeforeLoadHook && pendingNavigationIndex !== currentNavigationIndex) ) { return; }