@keenmate/svelte-spa-router 5.0.0-rc12 → 5.0.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/CHANGELOG.md +58 -4
- package/README.md +231 -34
- package/package.json +1 -2
- package/src/lib/Router.svelte +242 -42
- package/src/lib/helpers/error-handler.svelte.js +1 -1
- package/src/lib/helpers/hierarchy.svelte.js +23 -4
- package/src/lib/helpers/navigation-guard.svelte.js +1 -1
- package/src/lib/helpers/permissions.svelte.js +102 -3
- package/src/lib/helpers/querystring-helpers.svelte.js +1 -1
- package/src/lib/helpers/route-metadata.svelte.js +0 -2
- package/src/lib/index.js +2 -3
- package/src/lib/logger.ts +9 -8
- package/src/lib/utils.svelte.js +150 -65
package/CHANGELOG.md
CHANGED
|
@@ -7,7 +7,61 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
-
## [5.0.0
|
|
10
|
+
## [5.0.0] - 2025-01-17
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- **Code Quality:** Major ESLint cleanup - reduced linting issues from 161 to 11 (93% reduction)
|
|
14
|
+
- Removed unused imports across multiple modules (hierarchyLogger, location, untrack, hasRoute, etc.)
|
|
15
|
+
- Removed unused function parameters in test files
|
|
16
|
+
- Replaced unused catch error variables with bare catch blocks
|
|
17
|
+
- Added `src/lib/vendor/**` to eslint ignore list (third-party loglevel library)
|
|
18
|
+
- Remaining 11 warnings are false positives from ESLint not understanding Svelte 5 runes
|
|
19
|
+
- **Note:** If issues arise, this cleanup touched error-handler, hierarchy, navigation-guard, permissions, querystring-helpers, route-metadata, utils, and all test files
|
|
20
|
+
- **Logger API:** Renamed `enableCategory()` to `setCategoryLevel()` for better clarity
|
|
21
|
+
- Old name was confusing: `enableCategory('ROUTER:SCROLL', 'silent')` reads as "enable to disable"
|
|
22
|
+
- New name is explicit: `setCategoryLevel('ROUTER:SCROLL', 'silent')` clearly sets the level
|
|
23
|
+
- Added `'silent'` to TypeScript type definitions for level parameter
|
|
24
|
+
- No backward compatibility - clean break for clearer API
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
- **Breaking:** Standardized Router callback prop naming to camelCase (JavaScript convention)
|
|
28
|
+
- `onrouteLoading` → `onRouteLoading`
|
|
29
|
+
- `onrouteLoaded` → `onRouteLoaded`
|
|
30
|
+
- `onconditionsFailed` → `onConditionsFailed`
|
|
31
|
+
- `onNotFound` remains unchanged (already correct)
|
|
32
|
+
- Updated all documentation, examples, tests, and showcase site
|
|
33
|
+
- **Migration:** Update your Router component props to use camelCase naming
|
|
34
|
+
- **Permissions:** Completely redesigned unauthorized handling system
|
|
35
|
+
- Previously required manual `/unauthorized` route definition and `onUnauthorized` callback with hash-based navigation
|
|
36
|
+
- New system treats unauthorized state as special router state (like 404), not a regular route
|
|
37
|
+
- `/unauthorized` route no longer needs to be defined in routes object
|
|
38
|
+
- Respects configured routing mode (hash/history) instead of forcing hash navigation
|
|
39
|
+
- Two behavior modes available:
|
|
40
|
+
- `unauthorizedBehavior: 'component'` - Shows unauthorized component without changing URL (default)
|
|
41
|
+
- `unauthorizedBehavior: 'navigate'` - Navigates to configured unauthorized route
|
|
42
|
+
- Configure via `configurePermissions()` with new options: `unauthorizedBehavior`, `unauthorizedRoute`, `unauthorizedComponent`
|
|
43
|
+
- Router automatically detects permission failures by checking `routeContext.permissions`
|
|
44
|
+
- `createPermissionCondition()` only calls `onUnauthorized` handler if explicitly configured (backward compatibility)
|
|
45
|
+
- Added internal `hasExplicitHandler()` tracking to distinguish explicit callbacks from defaults
|
|
46
|
+
- **Migration:** Old `onUnauthorized` callback approach still works, new declarative config recommended
|
|
47
|
+
- **Referrer Tracking:** Fixed referrer not being preserved on browser back/forward navigation
|
|
48
|
+
- Previously, pressing back button would show chronological previous route as referrer instead of original referrer
|
|
49
|
+
- Example: `/` → `/links` (referrer: `/`) → `/query` (referrer: `/links`) → [BACK] → `/links` showed referrer `/query` (wrong!) instead of `/` (correct)
|
|
50
|
+
- Root cause: navigationContext with referrer was calculated by router but never saved to history.state
|
|
51
|
+
- Solution: Router now saves calculated navigationContext (with referrer) back to history.state after route loads
|
|
52
|
+
- Added serialization handling for Proxy objects in params (uses JSON serialization fallback when structuredClone fails)
|
|
53
|
+
- Applied to both hash mode and history mode navigation
|
|
54
|
+
- Navigation sequence tracking now correctly increments on forward and decrements on back
|
|
55
|
+
- `goBack()` function simplified to use native browser back (`window.history.back()`) instead of manual push
|
|
56
|
+
- Referrer and scroll position now automatically restored from history.state on back/forward navigation
|
|
57
|
+
- **Permissions:** Fixed `createProtectedRoute()` failing with synchronous component imports
|
|
58
|
+
- Error: "Cannot read properties of undefined (reading 'before')" when using sync imports like `component: AdminPanel`
|
|
59
|
+
- Root cause: `createProtectedRouteDefinition()` always treated components as async, causing Router to call component constructor as function returning `undefined`
|
|
60
|
+
- Solution: Detect sync vs async components - use `component` key for sync (let wrap() handle Promise wrapping) and `asyncComponent` key for async
|
|
61
|
+
- Now supports both patterns: `component: AdminPanel` (sync) and `component: () => import('./Admin.svelte')` (async)
|
|
62
|
+
- Async detection: `typeof component === 'function' && component.length === 0`
|
|
63
|
+
|
|
64
|
+
## [5.0.0-rc12] - 2025-02-12 ✅ Published
|
|
11
65
|
|
|
12
66
|
### Fixed
|
|
13
67
|
- **Critical:** Fixed missing TypeScript source files in published npm package
|
|
@@ -34,7 +88,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
34
88
|
- Uses vendored `loglevel` and `loglevel-plugin-prefix` libraries (ESM versions)
|
|
35
89
|
- **Breaking API change**: `setDebugLoggingEnabled()` replaced with new API
|
|
36
90
|
- Old: `import { setDebugLoggingEnabled } from '@keenmate/svelte-spa-router/utils'`
|
|
37
|
-
- New: `import { enableLogging, disableLogging, setLogLevel,
|
|
91
|
+
- New: `import { enableLogging, disableLogging, setLogLevel, setCategoryLevel } from '@keenmate/svelte-spa-router/logger'`
|
|
38
92
|
- **12 hierarchical categories** for granular control:
|
|
39
93
|
- `ROUTER` - Core routing pipeline, route matching
|
|
40
94
|
- `ROUTER:NAVIGATION` - push, pop, replace, goBack
|
|
@@ -53,8 +107,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
53
107
|
- **Per-category control**: Enable specific categories at different log levels
|
|
54
108
|
\`\`\`javascript
|
|
55
109
|
disableLogging() // Disable all
|
|
56
|
-
|
|
57
|
-
|
|
110
|
+
setCategoryLevel('ROUTER:SCROLL', 'debug') // Enable only scroll logs
|
|
111
|
+
setCategoryLevel('ROUTER:NAVIGATION', 'info') // Navigation at info level
|
|
58
112
|
\`\`\`
|
|
59
113
|
- **Global level control**: \`setLogLevel('warn')\` to set all categories at once
|
|
60
114
|
- Removed \`src/lib/internal/logging.js\` (custom implementation)
|
package/README.md
CHANGED
|
@@ -35,6 +35,135 @@ npm install @keenmate/svelte-spa-router
|
|
|
35
35
|
|
|
36
36
|
> **⚠️ Important:** This package requires **Node.js 22 or higher** for production builds. Node.js 20 has compatibility issues with Svelte 5 that may cause runtime errors like "link is not defined" in production builds. Make sure your build environment (CI/CD, Docker, etc.) uses Node 22+.
|
|
37
37
|
|
|
38
|
+
## Quick Start: Common Imports
|
|
39
|
+
|
|
40
|
+
Here are the most frequently used imports and where to get them:
|
|
41
|
+
|
|
42
|
+
### Basic Router Setup
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
// Main Router component
|
|
46
|
+
import Router from '@keenmate/svelte-spa-router'
|
|
47
|
+
|
|
48
|
+
// Navigation functions - available from main module OR /utils
|
|
49
|
+
import { push, replace, pop, goBack } from '@keenmate/svelte-spa-router'
|
|
50
|
+
// Alternative:
|
|
51
|
+
import { push, replace, pop, goBack } from '@keenmate/svelte-spa-router/utils'
|
|
52
|
+
|
|
53
|
+
// Link action for <a> tags
|
|
54
|
+
import { link } from '@keenmate/svelte-spa-router'
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Accessing Route Information
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
// Get current route data (call as functions, not stores!)
|
|
61
|
+
import { location, querystring, routeParams, navigationContext } from '@keenmate/svelte-spa-router'
|
|
62
|
+
|
|
63
|
+
// Usage in components:
|
|
64
|
+
const currentPath = $derived(location()) // e.g., "/user/123"
|
|
65
|
+
const query = $derived(querystring()) // e.g., "?tab=profile"
|
|
66
|
+
const params = $derived(routeParams()) // e.g., { id: "123" }
|
|
67
|
+
const context = $derived(navigationContext()) // Navigation context data
|
|
68
|
+
|
|
69
|
+
// Alternative: Access from /utils
|
|
70
|
+
import { location, querystring, routeParams } from '@keenmate/svelte-spa-router'
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**⚠️ Important:** In route components, prefer receiving `routeParams` as props instead of importing:
|
|
74
|
+
|
|
75
|
+
```svelte
|
|
76
|
+
<script>
|
|
77
|
+
// Recommended in route components
|
|
78
|
+
let { routeParams = {} } = $props()
|
|
79
|
+
</script>
|
|
80
|
+
|
|
81
|
+
<p>User ID: {routeParams.id}</p>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Route Configuration
|
|
85
|
+
|
|
86
|
+
```javascript
|
|
87
|
+
// Wrap routes with loading/conditions
|
|
88
|
+
import { wrap } from '@keenmate/svelte-spa-router/wrap'
|
|
89
|
+
|
|
90
|
+
// Active link highlighting
|
|
91
|
+
import active from '@keenmate/svelte-spa-router/active'
|
|
92
|
+
|
|
93
|
+
// Named routes system
|
|
94
|
+
import { registerRoutes, buildUrl } from '@keenmate/svelte-spa-router/routes'
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Advanced Features
|
|
98
|
+
|
|
99
|
+
```javascript
|
|
100
|
+
// Permission-based routing
|
|
101
|
+
import {
|
|
102
|
+
configurePermissions,
|
|
103
|
+
createProtectedRoute,
|
|
104
|
+
hasPermission
|
|
105
|
+
} from '@keenmate/svelte-spa-router/helpers/permissions'
|
|
106
|
+
|
|
107
|
+
// Navigation guards
|
|
108
|
+
import {
|
|
109
|
+
registerBeforeLeave,
|
|
110
|
+
unregisterBeforeLeave,
|
|
111
|
+
NavigationCancelledError
|
|
112
|
+
} from '@keenmate/svelte-spa-router/helpers/navigation-guard'
|
|
113
|
+
|
|
114
|
+
// Hierarchical route structure
|
|
115
|
+
import { createHierarchy } from '@keenmate/svelte-spa-router/helpers/hierarchy'
|
|
116
|
+
|
|
117
|
+
// Error handling
|
|
118
|
+
import {
|
|
119
|
+
configureGlobalErrorHandler
|
|
120
|
+
} from '@keenmate/svelte-spa-router/helpers/error-handler'
|
|
121
|
+
import { GlobalErrorHandler } from '@keenmate/svelte-spa-router/helpers/GlobalErrorHandler'
|
|
122
|
+
|
|
123
|
+
// URL utilities
|
|
124
|
+
import { joinPaths } from '@keenmate/svelte-spa-router/helpers/url-helpers'
|
|
125
|
+
|
|
126
|
+
// Query string helpers
|
|
127
|
+
import {
|
|
128
|
+
parseQuerystring,
|
|
129
|
+
stringifyQuerystring,
|
|
130
|
+
updateQuerystring
|
|
131
|
+
} from '@keenmate/svelte-spa-router/helpers/querystring'
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### All Available Import Paths
|
|
135
|
+
|
|
136
|
+
```javascript
|
|
137
|
+
'@keenmate/svelte-spa-router' // Main module (Router, push, location, etc.)
|
|
138
|
+
'@keenmate/svelte-spa-router/utils' // Alternative path for utils
|
|
139
|
+
'@keenmate/svelte-spa-router/wrap' // Route wrapping
|
|
140
|
+
'@keenmate/svelte-spa-router/active' // Active link action
|
|
141
|
+
'@keenmate/svelte-spa-router/routes' // Named routes system
|
|
142
|
+
'@keenmate/svelte-spa-router/constants' // Constants and enums
|
|
143
|
+
'@keenmate/svelte-spa-router/logger' // Debug logging
|
|
144
|
+
'@keenmate/svelte-spa-router/helpers/permissions' // Permission system
|
|
145
|
+
'@keenmate/svelte-spa-router/helpers/navigation-guard' // Navigation guards
|
|
146
|
+
'@keenmate/svelte-spa-router/helpers/hierarchy' // Hierarchical routes
|
|
147
|
+
'@keenmate/svelte-spa-router/helpers/error-handler' // Error handling
|
|
148
|
+
'@keenmate/svelte-spa-router/helpers/GlobalErrorHandler' // Error component
|
|
149
|
+
'@keenmate/svelte-spa-router/helpers/url-helpers' // URL utilities
|
|
150
|
+
'@keenmate/svelte-spa-router/helpers/querystring' // Query string helpers
|
|
151
|
+
'@keenmate/svelte-spa-router/helpers/route-metadata' // Breadcrumbs/metadata
|
|
152
|
+
'@keenmate/svelte-spa-router/helpers/filters' // Filter parsing
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**❌ Common Mistake:**
|
|
156
|
+
|
|
157
|
+
```javascript
|
|
158
|
+
// ❌ WRONG - /stores path doesn't exist (this was the old v3/v4 API)
|
|
159
|
+
import { routeParams } from '@keenmate/svelte-spa-router/stores'
|
|
160
|
+
|
|
161
|
+
// ✅ CORRECT - Import from main module or /utils
|
|
162
|
+
import { routeParams } from '@keenmate/svelte-spa-router'
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
> **Note:** This is a Svelte 5 router using runes (`$state`, `$derived`), not Svelte stores. There is no `/stores` export path.
|
|
166
|
+
|
|
38
167
|
## Debug Logging
|
|
39
168
|
|
|
40
169
|
The router includes a built-in debug logging system to help troubleshoot routing issues during development.
|
|
@@ -51,11 +180,11 @@ if (import.meta.env.DEV) {
|
|
|
51
180
|
}
|
|
52
181
|
|
|
53
182
|
// Or enable specific categories only
|
|
54
|
-
import { disableLogging,
|
|
183
|
+
import { disableLogging, setCategoryLevel } from '@keenmate/svelte-spa-router/logger'
|
|
55
184
|
|
|
56
185
|
disableLogging() // Disable all first
|
|
57
|
-
|
|
58
|
-
|
|
186
|
+
setCategoryLevel('ROUTER:SCROLL', 'debug') // Enable only scroll logs
|
|
187
|
+
setCategoryLevel('ROUTER:NAVIGATION', 'info') // Enable navigation at info level
|
|
59
188
|
```
|
|
60
189
|
|
|
61
190
|
### What Gets Logged
|
|
@@ -88,15 +217,15 @@ The router provides **12 hierarchical logging categories** for granular control:
|
|
|
88
217
|
### Advanced Logging Control
|
|
89
218
|
|
|
90
219
|
```javascript
|
|
91
|
-
import { setLogLevel,
|
|
220
|
+
import { setLogLevel, setCategoryLevel } from '@keenmate/svelte-spa-router/logger'
|
|
92
221
|
|
|
93
222
|
// Set global log level (affects all categories)
|
|
94
223
|
setLogLevel('warn') // Only show warnings and errors
|
|
95
224
|
|
|
96
225
|
// Enable specific categories at different levels
|
|
97
226
|
disableLogging() // Start with all disabled
|
|
98
|
-
|
|
99
|
-
|
|
227
|
+
setCategoryLevel('ROUTER:SCROLL', 'debug') // Debug scroll issues
|
|
228
|
+
setCategoryLevel('ROUTER:PERMISSIONS', 'info') // Monitor permission checks
|
|
100
229
|
```
|
|
101
230
|
|
|
102
231
|
**Log Levels:** `trace`, `debug`, `info`, `warn`, `error`, `silent`
|
|
@@ -233,7 +362,7 @@ Uses the History API with clean URLs like `http://example.com/path`.
|
|
|
233
362
|
```javascript
|
|
234
363
|
// main.js
|
|
235
364
|
import { mount } from 'svelte'
|
|
236
|
-
import { setHashRoutingEnabled, setBasePath } from '@keenmate/svelte-spa-router
|
|
365
|
+
import { setHashRoutingEnabled, setBasePath } from '@keenmate/svelte-spa-router'
|
|
237
366
|
import App from './App.svelte'
|
|
238
367
|
|
|
239
368
|
// Enable history mode
|
|
@@ -384,9 +513,12 @@ push({
|
|
|
384
513
|
navigationContext: { source: 'toolbar', userId: 789 }
|
|
385
514
|
})
|
|
386
515
|
|
|
387
|
-
// Go back
|
|
516
|
+
// Go back (browser back button)
|
|
388
517
|
pop()
|
|
389
518
|
|
|
519
|
+
// Go back to referrer (with scroll restoration) - requires referrer tracking
|
|
520
|
+
goBack()
|
|
521
|
+
|
|
390
522
|
// Replace current page (supports all formats above)
|
|
391
523
|
replace('/book/3')
|
|
392
524
|
replace(['bookDetail', { bookId: 456 }])
|
|
@@ -432,50 +564,115 @@ Navigation context:
|
|
|
432
564
|
|
|
433
565
|
### Referrer Tracking
|
|
434
566
|
|
|
435
|
-
Automatically track and
|
|
567
|
+
Automatically track and navigate back to the previous route with full context preservation.
|
|
568
|
+
|
|
569
|
+
#### Enabling Referrer Tracking
|
|
570
|
+
|
|
571
|
+
Configure in your main.js before mounting the app:
|
|
436
572
|
|
|
437
573
|
```javascript
|
|
438
|
-
// main.js
|
|
439
|
-
import { setIncludeReferrer } from '@keenmate/svelte-spa-router
|
|
574
|
+
// main.js
|
|
575
|
+
import { setIncludeReferrer } from '@keenmate/svelte-spa-router'
|
|
440
576
|
|
|
441
577
|
setIncludeReferrer('always') // Track referrer for all routes
|
|
442
|
-
// Options: 'never' (default), 'notfound' (404 only), 'always'
|
|
443
578
|
```
|
|
444
579
|
|
|
580
|
+
**Configuration Options:**
|
|
581
|
+
- `'never'` (default) - Disable referrer tracking
|
|
582
|
+
- `'notfound'` - Track referrer only for 404/catch-all routes
|
|
583
|
+
- `'always'` - Track referrer for all navigation
|
|
584
|
+
|
|
585
|
+
#### Using goBack() for "Go Back" Buttons
|
|
586
|
+
|
|
587
|
+
The `goBack()` helper provides the best way to navigate back with automatic scroll restoration:
|
|
588
|
+
|
|
589
|
+
```svelte
|
|
590
|
+
<script>
|
|
591
|
+
import { goBack, navigationContext } from '@keenmate/svelte-spa-router'
|
|
592
|
+
|
|
593
|
+
const navContext = $derived(navigationContext())
|
|
594
|
+
const referrer = $derived(navContext?.referrer)
|
|
595
|
+
</script>
|
|
596
|
+
|
|
597
|
+
{#if referrer}
|
|
598
|
+
<button onclick={goBack}>← Back to {referrer.location}</button>
|
|
599
|
+
{/if}
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
**How it works:**
|
|
603
|
+
- Navigates using browser's native back button (`window.history.back()`)
|
|
604
|
+
- Automatically restores scroll position from when you first visited that page
|
|
605
|
+
- Preserves the original referrer (not chronological previous route)
|
|
606
|
+
- Falls back to `pop()` if no referrer exists
|
|
607
|
+
|
|
608
|
+
> **⚠️ Important:** Use `goBack()` instead of manual `push(referrer.location)` to get automatic scroll restoration and proper back navigation behavior.
|
|
609
|
+
|
|
610
|
+
#### What Gets Tracked
|
|
611
|
+
|
|
612
|
+
The referrer object includes complete route context:
|
|
613
|
+
|
|
614
|
+
```javascript
|
|
615
|
+
{
|
|
616
|
+
location: '/documents/123', // Previous route path
|
|
617
|
+
querystring: 'tab=settings', // Query string
|
|
618
|
+
params: { id: '123' }, // Route parameters
|
|
619
|
+
routeName: 'documentDetail', // Named route (if using named routes)
|
|
620
|
+
scrollX: 0, // Scroll position when leaving
|
|
621
|
+
scrollY: 245 // Scroll position when leaving
|
|
622
|
+
}
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
#### How It Works
|
|
626
|
+
|
|
627
|
+
Referrers are automatically preserved in browser history:
|
|
628
|
+
|
|
629
|
+
1. When you navigate forward, the router calculates the referrer and saves it to `history.state`
|
|
630
|
+
2. When you press browser back/forward buttons, the referrer is restored from history
|
|
631
|
+
3. Referrer tracking respects your routing mode (hash or history API)
|
|
632
|
+
4. Scroll position is automatically saved and restored by `goBack()`
|
|
633
|
+
|
|
634
|
+
The referrer is cleared when users manually type a URL or refresh the page.
|
|
635
|
+
|
|
636
|
+
#### Advanced: Manual Navigation
|
|
637
|
+
|
|
638
|
+
For cases requiring custom logic before navigation:
|
|
639
|
+
|
|
445
640
|
```svelte
|
|
446
|
-
<!-- In any route component -->
|
|
447
641
|
<script>
|
|
448
|
-
import { push, navigationContext } from '@keenmate/svelte-spa-router
|
|
642
|
+
import { push, navigationContext } from '@keenmate/svelte-spa-router'
|
|
449
643
|
|
|
450
644
|
const navContext = $derived(navigationContext())
|
|
451
645
|
const referrer = $derived(navContext?.referrer)
|
|
452
646
|
|
|
453
|
-
function
|
|
454
|
-
if (referrer?.location) {
|
|
647
|
+
function customGoBack() {
|
|
648
|
+
if (!referrer?.location) {
|
|
649
|
+
// No referrer - fallback to home
|
|
650
|
+
push('/')
|
|
651
|
+
return
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// Custom logic before navigation
|
|
655
|
+
if (await confirmUnsavedChanges()) {
|
|
455
656
|
const url = referrer.querystring
|
|
456
657
|
? `${referrer.location}?${referrer.querystring}`
|
|
457
658
|
: referrer.location
|
|
458
659
|
push(url)
|
|
660
|
+
// Note: Manual push does NOT restore scroll position
|
|
459
661
|
}
|
|
460
662
|
}
|
|
461
663
|
</script>
|
|
462
|
-
|
|
463
|
-
{#if referrer}
|
|
464
|
-
<button onclick={goBack}>← Go Back to {referrer.location}</button>
|
|
465
|
-
{/if}
|
|
466
664
|
```
|
|
467
665
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
- `params` - Previous route parameters
|
|
472
|
-
- `routeName` - Previous route name (if using named routes)
|
|
666
|
+
> **Migration Note:** If you're currently using manual `push(referrer.location)` pattern, switch to `goBack()` for automatic scroll restoration and proper history navigation.
|
|
667
|
+
|
|
668
|
+
#### Benefits over history.back()
|
|
473
669
|
|
|
474
|
-
**
|
|
475
|
-
- Works
|
|
476
|
-
-
|
|
477
|
-
-
|
|
478
|
-
-
|
|
670
|
+
- **Automatic scroll restoration** - Returns to exact scroll position when you left
|
|
671
|
+
- **Preserved in browser history** - Works with browser back/forward buttons
|
|
672
|
+
- **Works with replace() navigation** - Referrer persists even when using `replace()`
|
|
673
|
+
- **Conditional logic** - Check referrer before navigating back
|
|
674
|
+
- **Full route context** - Access to params, querystring, route name
|
|
675
|
+
- **Custom fallback** - Redirect to home or other route when no referrer exists
|
|
479
676
|
|
|
480
677
|
### Strict Parameter Replacement
|
|
481
678
|
|
|
@@ -483,7 +680,7 @@ Configure how missing route parameters are handled:
|
|
|
483
680
|
|
|
484
681
|
```javascript
|
|
485
682
|
// main.js
|
|
486
|
-
import { setParamReplacementPlaceholder } from '@keenmate/svelte-spa-router
|
|
683
|
+
import { setParamReplacementPlaceholder } from '@keenmate/svelte-spa-router'
|
|
487
684
|
|
|
488
685
|
// Set placeholder for missing parameters (default: 'N-A')
|
|
489
686
|
setParamReplacementPlaceholder('N-A')
|
|
@@ -1522,7 +1719,7 @@ Define routes in a hierarchical tree structure as an alternative to flat definit
|
|
|
1522
1719
|
**Enable hierarchical mode first:**
|
|
1523
1720
|
```javascript
|
|
1524
1721
|
// main.js - before mounting app
|
|
1525
|
-
import { setHierarchicalRoutesEnabled } from '@keenmate/svelte-spa-router
|
|
1722
|
+
import { setHierarchicalRoutesEnabled } from '@keenmate/svelte-spa-router'
|
|
1526
1723
|
|
|
1527
1724
|
setHierarchicalRoutesEnabled(true)
|
|
1528
1725
|
```
|
|
@@ -1600,7 +1797,7 @@ const routes = {
|
|
|
1600
1797
|
import Router from '@keenmate/svelte-spa-router'
|
|
1601
1798
|
|
|
1602
1799
|
// Navigation utilities
|
|
1603
|
-
import { routeParams, navigationContext } from '@keenmate/svelte-spa-router'
|
|
1800
|
+
import { push, replace, pop, goBack, location, querystring, routeParams, navigationContext } from '@keenmate/svelte-spa-router'
|
|
1604
1801
|
|
|
1605
1802
|
// Named routes (for use with push/replace/link)
|
|
1606
1803
|
import { registerRoutes, buildUrl } from '@keenmate/svelte-spa-router/routes'
|
|
@@ -1618,7 +1815,7 @@ import { createHierarchy } from '@keenmate/svelte-spa-router/helpers/hierarchy'
|
|
|
1618
1815
|
import active from '@keenmate/svelte-spa-router/active'
|
|
1619
1816
|
|
|
1620
1817
|
// Configuration
|
|
1621
|
-
import { setHashRoutingEnabled, setBasePath, setParamReplacementPlaceholder, setHierarchicalRoutesEnabled } from '@keenmate/svelte-spa-router
|
|
1818
|
+
import { setHashRoutingEnabled, setBasePath, setParamReplacementPlaceholder, setHierarchicalRoutesEnabled } from '@keenmate/svelte-spa-router'
|
|
1622
1819
|
|
|
1623
1820
|
// Querystring helpers (shared reactive state)
|
|
1624
1821
|
import { configureQuerystring, query } from '@keenmate/svelte-spa-router/helpers/querystring'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keenmate/svelte-spa-router",
|
|
3
|
-
"version": "5.0.0
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Router for SPAs using Svelte 5 with runes, dual-mode routing, permissions, and error handling",
|
|
5
5
|
"main": "./src/lib/index.js",
|
|
6
6
|
"svelte": "./src/lib/Router.svelte",
|
|
@@ -21,7 +21,6 @@
|
|
|
21
21
|
"exports": {
|
|
22
22
|
".": {
|
|
23
23
|
"types": "./src/lib/index.d.ts",
|
|
24
|
-
"svelte": "./src/lib/Router.svelte",
|
|
25
24
|
"import": "./src/lib/index.js"
|
|
26
25
|
},
|
|
27
26
|
"./active": {
|