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

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