@keenmate/svelte-spa-router 2.0.1 → 5.0.0-rc04

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +317 -0
  2. package/LICENSE.md +21 -21
  3. package/README.md +1363 -507
  4. package/package.json +117 -72
  5. package/src/lib/Router.svelte +436 -0
  6. package/src/lib/active.d.ts +47 -0
  7. package/src/lib/active.svelte.js +157 -0
  8. package/src/lib/constants.d.ts +12 -0
  9. package/src/lib/constants.js +6 -0
  10. package/src/lib/helpers/filters.d.ts +158 -0
  11. package/src/lib/helpers/filters.svelte.js +291 -0
  12. package/src/lib/helpers/navigation-guard.d.ts +129 -0
  13. package/src/lib/helpers/navigation-guard.svelte.js +177 -0
  14. package/src/lib/helpers/permissions.d.ts +176 -0
  15. package/src/lib/helpers/permissions.svelte.js +255 -0
  16. package/src/lib/helpers/querystring-helpers.d.ts +92 -0
  17. package/src/lib/helpers/querystring-helpers.svelte.js +316 -0
  18. package/src/lib/helpers/querystring.d.ts +59 -0
  19. package/src/lib/helpers/querystring.svelte.js +74 -0
  20. package/src/lib/helpers/route-metadata.d.ts +190 -0
  21. package/src/lib/helpers/route-metadata.svelte.js +257 -0
  22. package/src/lib/helpers/url-helpers.d.ts +24 -0
  23. package/src/lib/helpers/url-helpers.svelte.js +48 -0
  24. package/src/lib/index.d.ts +19 -0
  25. package/src/lib/index.js +27 -0
  26. package/src/lib/parse-route.js +58 -0
  27. package/src/lib/routes.d.ts +76 -0
  28. package/src/lib/routes.svelte.js +115 -0
  29. package/src/lib/utils.d.ts +288 -0
  30. package/src/lib/utils.svelte.js +489 -0
  31. package/src/lib/wrap.d.ts +162 -0
  32. package/src/lib/wrap.js +232 -0
  33. package/.editorconfig +0 -21
  34. package/Router.d.ts +0 -225
  35. package/Router.svelte +0 -689
  36. package/active.d.ts +0 -23
  37. package/active.js +0 -121
  38. package/constants.js +0 -1
  39. package/helpers/url-helpers.js +0 -29
  40. package/nightwatch.conf.cjs +0 -52
  41. package/wrap.d.ts +0 -41
  42. package/wrap.js +0 -93
package/CHANGELOG.md ADDED
@@ -0,0 +1,317 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+
12
+ #### Convenient Route Creation API
13
+ - **New `createRoute()` and `createRouteDefinition()` functions** for easier route configuration
14
+ - `createRoute()` - Returns already wrapped component (most convenient, no `wrap()` needed)
15
+ - `createRouteDefinition()` - Returns route definition for use with `wrap()` (advanced use)
16
+ - Consistent API pattern matching `createProtectedRoute()` / `createProtectedRouteDefinition()`
17
+ - Support for `title` and `breadcrumbs` metadata directly in route options
18
+ - Automatic detection of sync vs async components
19
+
20
+ - **Enhanced Permission System**
21
+ - `createProtectedRoute()` - Now returns already wrapped component (breaking change from definition-only)
22
+ - `createProtectedRouteDefinition()` - New function that returns definition (replaces old `createProtectedRoute()` behavior)
23
+ - Maintains backward compatibility for existing `wrap(createProtectedRoute(...))` usage
24
+
25
+ - **Route Metadata Support**
26
+ - `title` - Set page title for routes
27
+ - `breadcrumbs` - Define breadcrumb trail with `{ label, path? }` structure
28
+ - Metadata stored in `userData` object, accessible in route events and components
29
+
30
+ #### Dynamic Metadata & Loading Control
31
+ - **Reactive Metadata Helpers**: `helpers/route-metadata.svelte.js`
32
+ - `routeTitle()` - Get current route title reactively
33
+ - `routeBreadcrumbs()` - Get current breadcrumb trail reactively
34
+ - `routeUserData()` - Get full route userData reactively
35
+ - `updateRouteMetadata(userData)` - Update metadata after data loads (e.g., change title from "Document" to "Invoice.pdf")
36
+ - **`updateTitle(title)` - Update just the title** (simpler than updateRouteMetadata)
37
+ - **`updateBreadcrumb(id, updates)` - Partial breadcrumb updates** (update specific segments by ID)
38
+ - Automatically updated by Router on route changes
39
+
40
+ - **Partial Breadcrumb Updates** (NEW!)
41
+ - Add `id` property to breadcrumb items in route config: `{ id: 'docDetail', label: 'Loading...', path: '/doc/:id' }`
42
+ - Update specific breadcrumbs after data loads: `updateBreadcrumb('docDetail', { label: 'Invoice.pdf', path: '/doc/123' })`
43
+ - **No need to replace the entire breadcrumbs array** - only update what changes!
44
+ - Perfect for nested paths: `/documents/:id/logs/:logId` where each segment needs dynamic data
45
+ - Static segments (Home, Documents, etc.) stay unchanged
46
+
47
+ - **Flexible Loading Control** with `shouldDisplayLoadingOnRouteLoad` flag
48
+ - **Pattern 1 (Router-managed with loadingComponent)**: Set `shouldDisplayLoadingOnRouteLoad: true` - Router keeps loading component visible until component calls `hideLoading()`
49
+ - **Pattern 2 (Component-managed)**: Default behavior - component handles its own loading state
50
+ - **Pattern 3 (Global overlay)**: User-defined global loading UI in App.svelte that reacts to `routeIsLoading()`
51
+ - `showLoading()` - Manually show loading state (triggers global overlay if defined)
52
+ - `hideLoading()` - Component signals data is loaded (hides loading component/overlay)
53
+ - `routeIsLoading()` - Check if route is currently loading (reactive state)
54
+ - Perfect for routes that fetch data and need dynamic titles/breadcrumbs
55
+ - Supports multi-zone layouts (toolpanel + content) with different loading UIs per zone
56
+
57
+ **Use cases**:
58
+ - Document detail page: Show "Document" while loading, then "Invoice template.pdf" after data loads
59
+ - User profile: Show "User Profile" while loading, then "John Doe" after data loads
60
+ - Product page: Show "Product" while loading, then "iPhone 15 Pro" after data loads
61
+ - Nested paths: `/documents/:id/logs` where both document name and "Logs" need to be in breadcrumbs
62
+
63
+ #### Named Routes Enhancement
64
+ - **Array/Object Syntax for Navigation**: `push()` and `replace()` functions now support the same convenient array/object syntax as the `link` action
65
+ - Array format: `push(['userProfile', { userId: 123 }, { tab: 'settings' }])`
66
+ - Object format: `push({ route: 'userProfile', params: { userId: 123 }, query: { tab: 'settings' } })`
67
+ - String format (legacy): `push('/about')` - still fully supported for backward compatibility
68
+ - Eliminates the need to manually call `buildUrl()` for programmatic navigation
69
+ - See `example-history/src/routes/LinksDemo.svelte` for interactive demos
70
+
71
+ ### Added - Querystring & Filter System
72
+
73
+ #### Querystring Helpers
74
+ - **Shared Reactive State**: `helpers/querystring.svelte.js`
75
+ - `configureQuerystring(options)` - Configure querystring parsing for entire app
76
+ - `query<T>()` - Get reactive parsed querystring with TypeScript generics
77
+ - Auto-detection of array formats (repeat vs comma-separated)
78
+ - Configure once, use everywhere pattern
79
+
80
+ - **Querystring Utilities**: `helpers/querystring-helpers.svelte.js`
81
+ - `parseQuerystring(qs, options)` - Parse querystring with array format support
82
+ - `stringifyQuerystring(obj, options)` - Convert object to querystring
83
+ - `getParsedQuerystring(options)` - Get parsed querystring (non-reactive)
84
+ - `updateQuerystring(updates, options)` - Update URL querystring (partial or full)
85
+ - `createQuerystringHelpers(parser, stringifier)` - Custom parser support
86
+
87
+ - **Array Format Support**:
88
+ - `'auto'` (default) - Auto-detects both repeat and comma formats
89
+ - `'repeat'` - `?tags=foo&tags=bar` (multiple parameters with same key)
90
+ - `'comma'` - `?tags=foo,bar,baz` (comma-separated values)
91
+
92
+ #### Filter System
93
+ - **Flexible Filters**: `helpers/filters.svelte.js`
94
+ - `configureFilters(options)` - Configure filter mode and parsing
95
+ - `filters<T>()` - Get reactive parsed filters with TypeScript generics
96
+ - `updateFilters<T>(updates, options)` - Update filters with type safety
97
+ - `getFiltersConfig()` - Get current filter configuration
98
+
99
+ - **Dual Mode Support**:
100
+ - **Flat Mode** (default): Each filter as separate query parameter
101
+ - Example: `?search=java&category=books&status=active`
102
+ - **Structured Mode**: Single parameter with custom syntax
103
+ - Example: `?$filter=search eq 'java' AND category eq 'books'`
104
+ - Supports custom parse/stringify functions for OData, Microsoft Graph API, etc.
105
+
106
+ #### TypeScript Support
107
+ - Full generic support for type-safe parameter access:
108
+ - `params<T>()` - Route parameters with intellisense
109
+ - `query<T>()` - Query parameters with intellisense
110
+ - `filters<T>()` - Filter parameters with intellisense
111
+ - `updateFilters<T>(updates, options)` - Type-safe filter updates
112
+
113
+ #### Value Handling
114
+ - **Filters**:
115
+ - `undefined` - Always removes the parameter
116
+ - `null` - Keeps parameter with empty value
117
+ - **Querystring**:
118
+ - `undefined` - Always removes the parameter
119
+ - `null` - Controlled by `dropNull` option (default: true removes it)
120
+ - Empty string - Controlled by `dropEmpty` option (default: false keeps it)
121
+
122
+ #### Example Applications
123
+ - `example-history/src/routes/QuerystringDemo.svelte` - Interactive querystring demo
124
+ - `example-history/src/routes/FiltersDemo.svelte` - Filter system with products demo
125
+ - `example-history/src/routes/RouteDataDemo.svelte` - Route data extraction examples
126
+
127
+ ### Fixed
128
+ - **Router Initialization**: Fixed location state initialization to be reactive to config changes
129
+ - Issue: Direct URL access (e.g., `http://localhost:5050/querystring-demo`) showed homepage
130
+ - Solution: Changed from `$state(getLocation())` to `$derived.by()` to react to config changes
131
+ - Now correctly reads `setHashRoutingEnabled()` before initializing location state
132
+
133
+ ### Documentation
134
+ - Updated `README.md` with comprehensive querystring and filter system documentation
135
+ - Added TypeScript generic examples throughout
136
+ - Added Quick Reference section with all available imports
137
+ - Updated main features list to highlight TypeScript and URL helpers
138
+
139
+ ## [1.0.0] - 2024
140
+
141
+ ### Package Information
142
+
143
+ - **Package Name:** @keenmate/svelte-spa-router
144
+ - **Publisher:** KeenMate (https://keenmate.com)
145
+ - **Repository:** https://github.com/keenmate/svelte-spa-router
146
+
147
+ ### Added - Svelte 5 Conversion
148
+
149
+ #### Core Router
150
+ - Complete rewrite using Svelte 5 runes (`$state`, `$props`, `$effect`)
151
+ - Reactive location tracking with rune-based state management
152
+ - Event handlers converted from `on:` directives to callback props
153
+ - Maintained full backward compatibility in route definition syntax
154
+
155
+ #### Dual-Mode Routing System
156
+ - **Hash Mode (Default)**: Traditional hash-based routing (`#/path`)
157
+ - No configuration required
158
+ - Works everywhere, including `file://` protocol
159
+ - Perfect for static hosting
160
+
161
+ - **History Mode (New)**: Clean URL routing (`/path`)
162
+ - Uses History API for clean URLs without hash
163
+ - Supports modifier keys (Ctrl+Click to open in new tab)
164
+ - Respects `target` attribute on links
165
+ - Requires server configuration to serve index.html for all routes
166
+
167
+ #### Configuration Functions
168
+ - `setHashRoutingEnabled(boolean)` - Toggle between hash and history mode
169
+ - `setBasePath(string)` - Set base path for history mode
170
+ - `getHashRoutingEnabled()` - Get current routing mode
171
+ - `getBasePath()` - Get current base path
172
+
173
+ #### Permission System (New)
174
+ - `helpers/permissions.svelte.js` - Comprehensive RBAC system
175
+ - `configurePermissions(config)` - Setup permission checking logic
176
+ - `createPermissionCondition(requirements)` - Create route guards
177
+ - `createProtectedRoute(options)` - Helper for protected routes
178
+ - `hasPermission(requirements)` - UI-level permission checking
179
+ - Support for `any` (OR) and `all` (AND) permission logic
180
+ - Flexible integration with existing route guards
181
+
182
+ #### URL Helpers
183
+ - `helpers/url-helpers.svelte.js` - Path manipulation utilities
184
+ - `joinPaths(...paths)` - Intelligent path joining with slash handling
185
+
186
+ #### Enhanced Active Link Detection
187
+ - Updated to work with both hash and history modes
188
+ - Automatic CSS class application on matching routes
189
+ - Pattern matching support
190
+
191
+ ### Changed
192
+
193
+ #### API Changes (Breaking)
194
+ - **Stores → Functions**:
195
+ - `$location` → `location()`
196
+ - `$querystring` → `querystring()`
197
+ - `$params` → `params()`
198
+ - `$loc` → `loc()`
199
+
200
+ - **Events → Props**:
201
+ - `on:routeLoading` → `onrouteLoading`
202
+ - `on:routeLoaded` → `onrouteLoaded`
203
+ - `on:conditionsFailed` → `onconditionsFailed`
204
+ - `on:routeEvent` → `onrouteEvent`
205
+
206
+ - **Component Props**:
207
+ - `export let params` → `let { params } = $props()`
208
+
209
+ - **Reactive Subscriptions**:
210
+ - `.subscribe()` → `$effect(() => { ... })`
211
+
212
+ ### Unchanged (Backward Compatible)
213
+
214
+ - ✅ Route definition syntax (same object/Map structure)
215
+ - ✅ `push()`, `pop()`, `replace()` navigation functions
216
+ - ✅ `link` action for anchor tags
217
+ - ✅ `active` action for link highlighting
218
+ - ✅ `wrap()` utility for async components and conditions
219
+ - ✅ Route guards/pre-conditions
220
+ - ✅ Dynamic imports and code-splitting
221
+ - ✅ Nested routers with prefix
222
+ - ✅ Scroll restoration
223
+ - ✅ Loading components
224
+
225
+ ### Documentation
226
+
227
+ #### New Files
228
+ - `CONTEXT.md` - Comprehensive project overview
229
+ - `CHANGELOG.md` - This file
230
+ - `DEVELOPMENT.md` - Development workflow guide
231
+ - `MIGRATION.md` - Detailed v4 → v5 migration guide
232
+ - `HASHLESS_MERGE_PLAN.md` - Technical implementation notes
233
+
234
+ #### Updated Files
235
+ - `README.md` - Added routing modes and permission system documentation
236
+ - `package.json` - Updated exports for new modules
237
+
238
+ ### Examples
239
+
240
+ - `example/` - Hash mode example (updated for Svelte 5)
241
+ - `example-history/` - History mode example (new)
242
+
243
+ ### Infrastructure
244
+
245
+ - ESLint configuration for Svelte 5
246
+ - Makefile for cross-platform development commands
247
+ - Package exports for all modules
248
+
249
+ ## Migration Guide
250
+
251
+ See [MIGRATION.md](./MIGRATION.md) for detailed instructions on upgrading from v4 to v5.
252
+
253
+ ### Quick Migration Checklist
254
+
255
+ 1. ✅ Update imports: `svelte-spa-router` → `@keenmate/svelte-spa-router`
256
+ 2. ✅ Change stores to functions: `$location` → `location()`
257
+ 3. ✅ Update event handlers: `on:routeLoaded` → `onrouteLoaded`
258
+ 4. ✅ Convert component props: `export let params` → `let { params } = $props()`
259
+ 5. ✅ Replace subscriptions with `$effect`
260
+ 6. ✅ Test all routes and navigation
261
+
262
+ ### Optional: Enable History Mode
263
+
264
+ ```javascript
265
+ // main.js
266
+ import { setHashRoutingEnabled, setBasePath } from '@keenmate/svelte-spa-router/utils'
267
+
268
+ setHashRoutingEnabled(false)
269
+ setBasePath('/')
270
+
271
+ mount(App, { target: document.body })
272
+ ```
273
+
274
+ ### Optional: Add Permission System
275
+
276
+ ```javascript
277
+ // main.js
278
+ import { configurePermissions } from '@keenmate/svelte-spa-router/helpers/permissions'
279
+
280
+ configurePermissions({
281
+ checkPermissions: (user, requirements) => {
282
+ // Your permission logic
283
+ },
284
+ getCurrentUser: () => getCurrentUser(),
285
+ onUnauthorized: (detail) => push('/unauthorized')
286
+ })
287
+ ```
288
+
289
+ ## Browser Compatibility
290
+
291
+ - **Svelte 5**: All modern browsers (Chrome, Firefox, Safari, Edge)
292
+ - **Hash Mode**: All browsers including IE10+
293
+ - **History Mode**: All browsers with History API support (IE10+)
294
+ - **Permissions**: All modern browsers
295
+
296
+ ## Dependencies
297
+
298
+ ### Runtime
299
+ - `regexparam@2.0.2` - Route pattern matching
300
+
301
+ ### Peer Dependencies
302
+ - `svelte@^5.0.0` - Required
303
+
304
+ ### Dev Dependencies
305
+ - `eslint@^9.0.0` - Code linting
306
+
307
+ ## Credits
308
+
309
+ - **Publisher:** KeenMate (https://keenmate.com)
310
+ - **Original svelte-spa-router:** Alessandro Segala (@ItalyPaleAle)
311
+ - **Svelte 5 Conversion:** KeenMate team
312
+ - **History Mode:** Adapted from svelte-spa-router-hashless
313
+ - **Permission System:** KeenMate team
314
+
315
+ ## License
316
+
317
+ MIT License - See [LICENSE.md](./LICENSE.md)
package/LICENSE.md CHANGED
@@ -1,21 +1,21 @@
1
- # The MIT License
2
-
3
- Copyright (c) 2019, Alessandro Segala
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
1
+ # The MIT License
2
+
3
+ Copyright (c) 2019, Alessandro Segala
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.