@keenmate/svelte-spa-router 5.0.0 → 5.1.1

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 CHANGED
@@ -5,9 +5,75 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [5.1.1] - 2025-11-30
9
+
10
+ ### Fixed
11
+ - **Breadcrumbs preserved on querystring changes** - Fixed breadcrumbs resetting to "Loading..." when only the querystring changes (e.g., tab navigation)
12
+ - Issue: Changing tabs via `replace('/items/1', {}, { tab: 'settings' })` would reset dynamically updated breadcrumbs back to their initial "Loading..." state
13
+ - Root cause: `updateRouteMetadata()` was resetting the entire route context on any navigation, including querystring-only changes
14
+ - Solution: Detect when only querystring changed (same location + params) and preserve current breadcrumbs instead of resetting
15
+ - Also applies cached breadcrumb updates when the route context is updated
16
+
17
+ ### Added
18
+ - **TabsDemo example** - New example demonstrating correct pattern for tabs with querystring state
19
+ - Shows how to use `replace()` instead of `push()` for tab changes
20
+ - Demonstrates dynamic breadcrumbs that persist across tab switches
21
+ - Located at `example/src/routes/TabsDemo.svelte`
22
+
23
+ ### Documentation
24
+ - **AI Documentation Index** - Added comprehensive `ai/INDEX.txt` file for quick keyword lookup
25
+ - Organized by topic sections: Getting Started, Imports, Navigation, Named Routes, etc.
26
+ - Includes file descriptions, reading order recommendations, and cross-references
27
+ - Quick problem solving guide mapping common errors to solutions
28
+ - Examples organized by use case (Simple SPA, Admin Dashboard, E-commerce, etc.)
29
+ - **Breadcrumbs with Tabs** - Added "TABS WITH QUERY STRING" section to `ai/breadcrumbs.txt`
30
+ - Documents the pattern for tabs that use querystring for state
31
+ - Explains why `replace()` is necessary to preserve breadcrumbs
32
+ - Includes complete code example
33
+ - **Named Routes in Basic Setup** - Added "ENABLING NAMED ROUTES" section to `ai/basic-setup.txt`
34
+ - Documents that `registerRoutes()` must be called for named route navigation to work
35
+ - Shows common pattern with page definitions array
36
+ - Explains the "Route X not found in registry" error and how to fix it
37
+
8
38
  ## [Unreleased]
9
39
 
10
- ## [5.0.0] - 2025-01-17
40
+ ### Documentation
41
+ - **AI Assistant Documentation** - Added 15 concise text files in `./ai` folder optimized for AI assistants
42
+ - Plain text format (no markdown) with bullet-style structure for efficient AI parsing
43
+ - Files organized by feature: basic-setup, navigation, named-routes, route-params, permissions, guards-conditions, hierarchical-routes, tree-structure, link-actions, error-handling, referrer-tracking, debug-logging, import-patterns, utilities, breadcrumbs
44
+ - Includes correct/incorrect usage patterns (✅/❌) for common mistakes
45
+ - Code examples designed for copy-paste usage
46
+ - Complements CLAUDE.md by providing quick-reference documentation
47
+ - Aimed at helping AI coding assistants (like Claude, Cursor, Copilot) quickly understand router functionality
48
+ - **Breadcrumbs Documentation** - Added comprehensive `ai/breadcrumbs.txt` covering breadcrumb navigation system
49
+ - Basic breadcrumb definition and structure
50
+ - Accessing breadcrumbs in components via `routeBreadcrumbs()` helper
51
+ - Breadcrumb component examples with navigation and styling
52
+ - Dynamic breadcrumb updates using `updateBreadcrumb(id, updates)` after data loads
53
+ - Integration with route parameters for dynamic segments
54
+ - Hierarchical breadcrumb inheritance with automatic concatenation
55
+ - Tree structure support with `createHierarchy()`
56
+ - Best practices and common patterns
57
+ - Debugging with ROUTER:METADATA logging category
58
+
59
+ ## [5.1.0] - 2025-11-20 ✅ Published
60
+
61
+ ### Added
62
+ - **Global Window API:** Added runtime debugging and introspection via `window.components['svelte-spa-router']`
63
+ - `version()` - Get library version at runtime
64
+ - `config` - Access package metadata (name, version, author, license, repository, homepage)
65
+ - `logging.enableLogging()` - Enable all debug logging from browser console
66
+ - `logging.disableLogging()` - Disable all logging from browser console
67
+ - `logging.setLogLevel(level)` - Set global log level from browser console
68
+ - `logging.setCategoryLevel(category, level)` - Control specific logging categories from browser console
69
+ - `logging.getCategories()` - List all available logging categories
70
+ - TypeScript support with full autocompletion for global API
71
+ - SSR-safe implementation (only initializes in browser)
72
+ - Namespace-safe pattern using `window.components` (shared across all component libraries)
73
+ - Enables debugging production issues without code changes or rebuilding
74
+ - Example: `window.components['svelte-spa-router'].logging.setCategoryLevel('ROUTER:NAVIGATION', 'debug')`
75
+
76
+ ## [5.0.0] - 2025-01-17 ✅ Published
11
77
 
12
78
  ### Changed
13
79
  - **Code Quality:** Major ESLint cleanup - reduced linting issues from 161 to 11 (93% reduction)
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.1.1",
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",
@@ -595,11 +595,6 @@ function commitToReactiveState(ctx) {
595
595
  }
596
596
  }
597
597
 
598
- // Debug log AFTER navigationContext is set
599
- const finalReferrer = ctx.updatedNavigationContext?.referrer?.location || 'none'
600
- const finalSeq = typeof window !== 'undefined' && window.history.state?.__navigationSequence || 0
601
- console.log(`🔍 NAV: route="${ctx.location}" referrer="${finalReferrer}" seq=${finalSeq}`)
602
-
603
598
  // Update current route tracking (unless catch-all)
604
599
  if (!ctx.isCatchAll) {
605
600
  currentRoute = ctx.location
@@ -42,8 +42,11 @@ let updatedBreadcrumbsCache = new Map()
42
42
  * @param {Object} params - route params
43
43
  */
44
44
  export function updateRouteMetadata(routeContext = {}, location = '', querystring = '', params = {}) {
45
- // Create a unique key for this route (location + querystring + params)
46
- const routeKey = `${location}|${querystring}|${JSON.stringify(params)}`
45
+ // Create a key for the route path (without querystring) to detect actual route changes
46
+ const locationKey = `${location}|${JSON.stringify(params)}`
47
+
48
+ // Create full key including querystring for logging
49
+ const fullRouteKey = `${location}|${querystring}|${JSON.stringify(params)}`
47
50
 
48
51
  // Extract base path (e.g., /documents/1 → /documents, /documents/1/logs → /documents/1)
49
52
  // This is a simple heuristic: get path up to the last segment
@@ -56,12 +59,45 @@ export function updateRouteMetadata(routeContext = {}, location = '', querystrin
56
59
  clearBreadcrumbCache()
57
60
  }
58
61
 
59
- // Only update if route actually changed
60
- if (currentRouteKey !== routeKey) {
61
- currentRouterouteContext = routeContext
62
- currentRouteKey = routeKey
63
- currentBasePath = basePath
64
- metadataLogger.debug('[updateRouteMetadata] Route changed to:', routeKey)
62
+ // Check if only querystring changed (same location and params)
63
+ const onlyQuerystringChanged = currentRouteKey && currentRouteKey.startsWith(locationKey.split('|')[0] + '|')
64
+ && currentRouteKey.includes('|' + JSON.stringify(params))
65
+ && currentRouteKey !== fullRouteKey
66
+
67
+ // Only update context if the actual route (location + params) changed, not just querystring
68
+ if (currentRouteKey !== fullRouteKey) {
69
+ if (onlyQuerystringChanged) {
70
+ // Querystring-only change: preserve breadcrumbs, just update the key
71
+ metadataLogger.debug('[updateRouteMetadata] Querystring changed, preserving breadcrumbs')
72
+ currentRouteKey = fullRouteKey
73
+ } else {
74
+ // Actual route change: update context but apply cached breadcrumb updates
75
+ let finalContext = { ...routeContext }
76
+
77
+ // Apply any cached breadcrumb updates to the new context
78
+ if (routeContext.breadcrumbs && updatedBreadcrumbsCache.size > 0) {
79
+ const breadcrumbs = [...routeContext.breadcrumbs]
80
+ let appliedUpdates = false
81
+
82
+ for (const [id, updates] of updatedBreadcrumbsCache) {
83
+ const index = breadcrumbs.findIndex(crumb => crumb.id === id)
84
+ if (index !== -1) {
85
+ breadcrumbs[index] = { ...breadcrumbs[index], ...updates }
86
+ appliedUpdates = true
87
+ metadataLogger.debug('[updateRouteMetadata] Applied cached update for:', id)
88
+ }
89
+ }
90
+
91
+ if (appliedUpdates) {
92
+ finalContext = { ...finalContext, breadcrumbs }
93
+ }
94
+ }
95
+
96
+ currentRouterouteContext = finalContext
97
+ currentRouteKey = fullRouteKey
98
+ currentBasePath = basePath
99
+ metadataLogger.debug('[updateRouteMetadata] Route changed to:', fullRouteKey)
100
+ }
65
101
  } else {
66
102
  metadataLogger.debug('[updateRouteMetadata] Same route, ignoring update')
67
103
  }
package/src/lib/index.js CHANGED
@@ -24,3 +24,73 @@ export * from './helpers/filters.svelte.js';
24
24
 
25
25
  // Navigation guard system
26
26
  export * from './helpers/navigation-guard.svelte.js';
27
+
28
+ // Import logging utilities for global API
29
+ import {
30
+ enableLogging,
31
+ disableLogging,
32
+ setLogLevel,
33
+ setCategoryLevel
34
+ } from './logger';
35
+
36
+ /**
37
+ * @typedef {Object} GlobalRouterAPI
38
+ * @property {() => string} version - Get library version
39
+ * @property {Object} config - Package metadata
40
+ * @property {string} config.name - Package name
41
+ * @property {string} config.version - Package version
42
+ * @property {string} config.author - Package author
43
+ * @property {string} config.license - Package license
44
+ * @property {string} config.repository - Repository URL
45
+ * @property {string} config.homepage - Homepage URL
46
+ * @property {Object} logging - Logging controls
47
+ * @property {() => void} logging.enableLogging - Enable all debug logging
48
+ * @property {() => void} logging.disableLogging - Disable all logging
49
+ * @property {(level: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent') => void} logging.setLogLevel - Set global log level
50
+ * @property {(category: string, level?: string) => void} logging.setCategoryLevel - Set category-specific log level
51
+ * @property {() => string[]} logging.getCategories - List all logging categories
52
+ */
53
+
54
+ // List of all logging categories
55
+ const LOGGING_CATEGORIES = [
56
+ 'ROUTER',
57
+ 'ROUTER:NAVIGATION',
58
+ 'ROUTER:SCROLL',
59
+ 'ROUTER:GUARDS',
60
+ 'ROUTER:CONDITIONS',
61
+ 'ROUTER:HIERARCHY',
62
+ 'ROUTER:PERMISSIONS',
63
+ 'ROUTER:ROUTES',
64
+ 'ROUTER:ZONES',
65
+ 'ROUTER:METADATA',
66
+ 'ROUTER:ERROR_HANDLER',
67
+ 'ROUTER:FILTERS'
68
+ ];
69
+
70
+ // Initialize global API (SSR-safe)
71
+ if (typeof window !== 'undefined') {
72
+ // Create components namespace if it doesn't exist
73
+ window.components = window.components || {};
74
+
75
+ // Initialize svelte-spa-router API
76
+ // Note: __VERSION__, __PACKAGE_NAME__, etc. are injected by build tools (Vite, Rollup)
77
+ // via the `define` option. Fallback values are provided for source distribution.
78
+ window.components['svelte-spa-router'] = {
79
+ version: () => typeof __VERSION__ !== 'undefined' ? __VERSION__ : '5.1.0',
80
+ config: {
81
+ name: typeof __PACKAGE_NAME__ !== 'undefined' ? __PACKAGE_NAME__ : '@keenmate/svelte-spa-router',
82
+ version: typeof __VERSION__ !== 'undefined' ? __VERSION__ : '5.1.0',
83
+ author: typeof __AUTHOR__ !== 'undefined' ? __AUTHOR__ : 'KeenMate (https://keenmate.com)',
84
+ license: typeof __LICENSE__ !== 'undefined' ? __LICENSE__ : 'MIT',
85
+ repository: typeof __REPOSITORY__ !== 'undefined' ? __REPOSITORY__ : 'https://github.com/keenmate/svelte-spa-router',
86
+ homepage: typeof __HOMEPAGE__ !== 'undefined' ? __HOMEPAGE__ : 'https://github.com/keenmate/svelte-spa-router#readme'
87
+ },
88
+ logging: {
89
+ enableLogging,
90
+ disableLogging,
91
+ setLogLevel,
92
+ setCategoryLevel,
93
+ getCategories: () => [...LOGGING_CATEGORIES]
94
+ }
95
+ };
96
+ }