diff --git a/.changeset/silent-numbers-itch.md b/.changeset/silent-numbers-itch.md new file mode 100644 index 00000000..f631449d --- /dev/null +++ b/.changeset/silent-numbers-itch.md @@ -0,0 +1,5 @@ +--- +'sv-router': patch +--- + +return navigation "error" inside `navigate` diff --git a/src/create-router.svelte.js b/src/create-router.svelte.js index 7fc05a3d..e1c4f91c 100644 --- a/src/create-router.svelte.js +++ b/src/create-router.svelte.js @@ -12,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} */ @@ -118,7 +119,7 @@ export function createRouter(r) { function navigate(path, options = {}) { if (typeof path === 'number') { globalThis.history.go(path); - return; + return new Navigation(`History entry: ${path}`); } path = constructPath(path, options.params); @@ -128,6 +129,7 @@ function navigate(path, options = {}) { options.hash = '#' + options.hash; } onNavigate(path, options); + return new Navigation(`${path}${serializeSearch(options?.search ?? '')}${options?.hash ?? ''}`); } /** @@ -142,7 +144,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); @@ -220,7 +222,7 @@ export async function onNavigate(path, options = {}) { /** @param {string} [path] */ function getMatchPath(path) { - let matchPath = ''; + let matchPath; if (path) { matchPath = path; diff --git a/src/index.d.ts b/src/index.d.ts index a190963d..1ffae9b8 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. @@ -139,8 +143,9 @@ export type RouterApi = { * * @param route The route to navigate to. * @param options The navigation options. + * @returns {@link Navigation} For use with `throw navigate(...)` inside hooks. */ - navigate>(...args: NavigateArgs): void; + navigate>(...args: NavigateArgs): Navigation; /** * Will return `true` if the given path is active. diff --git a/src/index.js b/src/index.js index 15091c08..802c7740 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 00000000..ad2719a7 --- /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'; + } +}