eleva 1.0.1 → 1.1.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/README.md +21 -10
- package/dist/{eleva-plugins.cjs.js → eleva-plugins.cjs} +1002 -292
- package/dist/eleva-plugins.cjs.map +1 -0
- package/dist/eleva-plugins.d.cts +1352 -0
- package/dist/eleva-plugins.d.cts.map +1 -0
- package/dist/eleva-plugins.d.ts +1352 -0
- package/dist/eleva-plugins.d.ts.map +1 -0
- package/dist/{eleva-plugins.esm.js → eleva-plugins.js} +1002 -292
- package/dist/eleva-plugins.js.map +1 -0
- package/dist/eleva-plugins.umd.js +1001 -291
- package/dist/eleva-plugins.umd.js.map +1 -1
- package/dist/eleva-plugins.umd.min.js +1 -1
- package/dist/eleva-plugins.umd.min.js.map +1 -1
- package/dist/{eleva.cjs.js → eleva.cjs} +421 -191
- package/dist/eleva.cjs.map +1 -0
- package/dist/eleva.d.cts +1329 -0
- package/dist/eleva.d.cts.map +1 -0
- package/dist/eleva.d.ts +473 -226
- package/dist/eleva.d.ts.map +1 -0
- package/dist/{eleva.esm.js → eleva.js} +422 -192
- package/dist/eleva.js.map +1 -0
- package/dist/eleva.umd.js +420 -190
- package/dist/eleva.umd.js.map +1 -1
- package/dist/eleva.umd.min.js +1 -1
- package/dist/eleva.umd.min.js.map +1 -1
- package/dist/plugins/attr.cjs +279 -0
- package/dist/plugins/attr.cjs.map +1 -0
- package/dist/plugins/attr.d.cts +101 -0
- package/dist/plugins/attr.d.cts.map +1 -0
- package/dist/plugins/attr.d.ts +101 -0
- package/dist/plugins/attr.d.ts.map +1 -0
- package/dist/plugins/attr.js +276 -0
- package/dist/plugins/attr.js.map +1 -0
- package/dist/plugins/attr.umd.js +111 -22
- package/dist/plugins/attr.umd.js.map +1 -1
- package/dist/plugins/attr.umd.min.js +1 -1
- package/dist/plugins/attr.umd.min.js.map +1 -1
- package/dist/plugins/router.cjs +1873 -0
- package/dist/plugins/router.cjs.map +1 -0
- package/dist/plugins/router.d.cts +1296 -0
- package/dist/plugins/router.d.cts.map +1 -0
- package/dist/plugins/router.d.ts +1296 -0
- package/dist/plugins/router.d.ts.map +1 -0
- package/dist/plugins/router.js +1870 -0
- package/dist/plugins/router.js.map +1 -0
- package/dist/plugins/router.umd.js +482 -186
- package/dist/plugins/router.umd.js.map +1 -1
- package/dist/plugins/router.umd.min.js +1 -1
- package/dist/plugins/router.umd.min.js.map +1 -1
- package/dist/plugins/store.cjs +920 -0
- package/dist/plugins/store.cjs.map +1 -0
- package/dist/plugins/store.d.cts +266 -0
- package/dist/plugins/store.d.cts.map +1 -0
- package/dist/plugins/store.d.ts +266 -0
- package/dist/plugins/store.d.ts.map +1 -0
- package/dist/plugins/store.js +917 -0
- package/dist/plugins/store.js.map +1 -0
- package/dist/plugins/store.umd.js +410 -85
- package/dist/plugins/store.umd.js.map +1 -1
- package/dist/plugins/store.umd.min.js +1 -1
- package/dist/plugins/store.umd.min.js.map +1 -1
- package/package.json +112 -68
- package/src/core/Eleva.js +195 -115
- package/src/index.cjs +10 -0
- package/src/index.js +11 -0
- package/src/modules/Emitter.js +68 -20
- package/src/modules/Renderer.js +82 -20
- package/src/modules/Signal.js +43 -15
- package/src/modules/TemplateEngine.js +50 -9
- package/src/plugins/Attr.js +121 -19
- package/src/plugins/Router.js +526 -181
- package/src/plugins/Store.js +448 -69
- package/src/plugins/index.js +1 -0
- package/types/core/Eleva.d.ts +263 -169
- package/types/core/Eleva.d.ts.map +1 -1
- package/types/index.d.cts +3 -0
- package/types/index.d.cts.map +1 -0
- package/types/index.d.ts +5 -0
- package/types/index.d.ts.map +1 -1
- package/types/modules/Emitter.d.ts +73 -30
- package/types/modules/Emitter.d.ts.map +1 -1
- package/types/modules/Renderer.d.ts +48 -18
- package/types/modules/Renderer.d.ts.map +1 -1
- package/types/modules/Signal.d.ts +44 -16
- package/types/modules/Signal.d.ts.map +1 -1
- package/types/modules/TemplateEngine.d.ts +46 -11
- package/types/modules/TemplateEngine.d.ts.map +1 -1
- package/types/plugins/Attr.d.ts +83 -16
- package/types/plugins/Attr.d.ts.map +1 -1
- package/types/plugins/Router.d.ts +498 -207
- package/types/plugins/Router.d.ts.map +1 -1
- package/types/plugins/Store.d.ts +211 -37
- package/types/plugins/Store.d.ts.map +1 -1
- package/dist/eleva-plugins.cjs.js.map +0 -1
- package/dist/eleva-plugins.esm.js.map +0 -1
- package/dist/eleva.cjs.js.map +0 -1
- package/dist/eleva.esm.js.map +0 -1
package/src/plugins/Router.js
CHANGED
|
@@ -1,75 +1,234 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
+
* @module eleva/plugins/router
|
|
5
|
+
* @fileoverview Client-side router plugin with hash, history, and query modes,
|
|
6
|
+
* navigation guards, and lifecycle hooks.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// TYPE DEFINITIONS
|
|
11
|
+
// ============================================================================
|
|
12
|
+
|
|
13
|
+
// -----------------------------------------------------------------------------
|
|
14
|
+
// External Type Imports
|
|
15
|
+
// -----------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Type imports from the Eleva core library.
|
|
4
19
|
* @typedef {import('eleva').Eleva} Eleva
|
|
5
|
-
* @typedef {import('eleva').Signal} Signal
|
|
6
20
|
* @typedef {import('eleva').ComponentDefinition} ComponentDefinition
|
|
7
21
|
* @typedef {import('eleva').Emitter} Emitter
|
|
8
22
|
* @typedef {import('eleva').MountResult} MountResult
|
|
23
|
+
* @typedef {import('eleva').UnsubscribeFunction} UnsubscribeFunction
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Generic type import.
|
|
28
|
+
* @template T
|
|
29
|
+
* @typedef {import('eleva').Signal<T>} Signal
|
|
9
30
|
*/
|
|
10
31
|
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
32
|
+
// -----------------------------------------------------------------------------
|
|
33
|
+
// Router Events
|
|
34
|
+
// -----------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Fired when the router initialization completes successfully.
|
|
38
|
+
* @event router:ready
|
|
39
|
+
* @type {Router}
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Fired when an error occurs during navigation or route handling.
|
|
44
|
+
* @event router:error
|
|
45
|
+
* @type {Error}
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Fired when no matching route is found for the requested path.
|
|
50
|
+
* @event router:notFound
|
|
51
|
+
* @type {{to: RouteLocation, from: RouteLocation | null, path: string}}
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Fired before guards run, allowing plugins to block or redirect navigation.
|
|
56
|
+
* @event router:beforeEach
|
|
57
|
+
* @type {NavigationContext}
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Fired before component resolution, allowing plugins to modify the resolve context.
|
|
62
|
+
* @event router:beforeResolve
|
|
63
|
+
* @type {ResolveContext}
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Fired after components are resolved successfully.
|
|
68
|
+
* @event router:afterResolve
|
|
69
|
+
* @type {ResolveContext}
|
|
70
|
+
*/
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Fired after leaving the previous route.
|
|
74
|
+
* @event router:afterLeave
|
|
75
|
+
* @type {{to: RouteLocation, from: RouteLocation}}
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Fired before DOM rendering begins.
|
|
80
|
+
* @event router:beforeRender
|
|
81
|
+
* @type {RenderContext}
|
|
82
|
+
*/
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Fired after DOM rendering completes.
|
|
86
|
+
* @event router:afterRender
|
|
87
|
+
* @type {RenderContext}
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Fired after render for scroll behavior handling.
|
|
92
|
+
* @event router:scroll
|
|
93
|
+
* @type {ScrollContext}
|
|
94
|
+
*/
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Fired after entering the new route.
|
|
98
|
+
* @event router:afterEnter
|
|
99
|
+
* @type {{to: RouteLocation, from: RouteLocation | null}}
|
|
100
|
+
*/
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Fired after navigation completes successfully.
|
|
104
|
+
* @event router:afterEach
|
|
105
|
+
* @type {{to: RouteLocation, from: RouteLocation | null}}
|
|
106
|
+
*/
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Fired when a route is dynamically added.
|
|
110
|
+
* @event router:routeAdded
|
|
111
|
+
* @type {RouteDefinition}
|
|
112
|
+
*/
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Fired when a route is dynamically removed.
|
|
116
|
+
* @event router:routeRemoved
|
|
117
|
+
* @type {RouteDefinition}
|
|
118
|
+
*/
|
|
119
|
+
|
|
120
|
+
// -----------------------------------------------------------------------------
|
|
121
|
+
// Router Data Types
|
|
122
|
+
// -----------------------------------------------------------------------------
|
|
14
123
|
|
|
15
124
|
/**
|
|
16
|
-
* @typedef {'hash' | 'history' | 'query'} RouterMode
|
|
17
125
|
* The routing mode determines how the router manages URL state.
|
|
18
126
|
* - `hash`: Uses URL hash (e.g., `/#/path`) - works without server config
|
|
19
127
|
* - `history`: Uses HTML5 History API (e.g., `/path`) - requires server config
|
|
20
128
|
* - `query`: Uses query parameters (e.g., `?view=/path`) - useful for embedded apps
|
|
129
|
+
* @typedef {'hash' | 'history' | 'query'} RouterMode
|
|
130
|
+
*/
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Route parameters extracted from the URL path.
|
|
134
|
+
* @typedef {Record<string, string>} RouteParams
|
|
135
|
+
* @description Key-value pairs extracted from dynamic route segments (e.g., `/users/:id` → `{ id: '123' }`).
|
|
21
136
|
*/
|
|
22
137
|
|
|
23
138
|
/**
|
|
139
|
+
* Query parameters from the URL query string.
|
|
140
|
+
* @typedef {Record<string, string>} QueryParams
|
|
141
|
+
* @description Key-value pairs from the URL query string (e.g., `?page=1&sort=name`).
|
|
142
|
+
*/
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Navigation input parameters supporting multiple value types.
|
|
146
|
+
* @typedef {Record<string, string | number | boolean>} NavigationParams
|
|
147
|
+
* @description Parameters passed to navigation functions, automatically converted to strings in URLs.
|
|
148
|
+
*/
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Function signature for programmatic navigation.
|
|
152
|
+
* @typedef {(location: string | NavigationTarget, params?: NavigationParams) => Promise<boolean>} NavigateFunction
|
|
153
|
+
* @description Returns true if navigation succeeded, false if blocked by a guard.
|
|
154
|
+
*/
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Router configuration options.
|
|
24
158
|
* @typedef {Object} RouterOptions
|
|
25
|
-
* @property {RouterMode} [mode='hash']
|
|
26
|
-
*
|
|
27
|
-
* @property {string} [
|
|
28
|
-
*
|
|
29
|
-
* @property {
|
|
30
|
-
*
|
|
31
|
-
* @property {
|
|
159
|
+
* @property {RouterMode} [mode='hash']
|
|
160
|
+
* The routing mode to use.
|
|
161
|
+
* @property {string} [queryParam='view']
|
|
162
|
+
* Query parameter name for 'query' mode.
|
|
163
|
+
* @property {string} [viewSelector='view']
|
|
164
|
+
* Base selector for the view element.
|
|
165
|
+
* @property {string} mount
|
|
166
|
+
* CSS selector for the mount point element.
|
|
167
|
+
* @property {RouteDefinition[]} routes
|
|
168
|
+
* Array of route definitions.
|
|
169
|
+
* @property {RouteComponent} [globalLayout]
|
|
170
|
+
* Default layout for all routes.
|
|
171
|
+
* @property {NavigationGuard} [onBeforeEach]
|
|
172
|
+
* Global navigation guard.
|
|
173
|
+
* @property {boolean} [autoStart=true]
|
|
174
|
+
* Whether to start the router automatically.
|
|
32
175
|
* @description Configuration options for the Router plugin.
|
|
33
176
|
*/
|
|
34
177
|
|
|
35
178
|
/**
|
|
179
|
+
* Object describing a navigation target for `router.navigate()`.
|
|
36
180
|
* @typedef {Object} NavigationTarget
|
|
37
|
-
* @property {string} path
|
|
38
|
-
*
|
|
39
|
-
* @property {
|
|
40
|
-
*
|
|
41
|
-
* @property {
|
|
181
|
+
* @property {string} path
|
|
182
|
+
* The target path (can include params like '/users/:id').
|
|
183
|
+
* @property {NavigationParams} [params]
|
|
184
|
+
* Route parameters to inject.
|
|
185
|
+
* @property {NavigationParams} [query]
|
|
186
|
+
* Query parameters to append.
|
|
187
|
+
* @property {boolean} [replace=false]
|
|
188
|
+
* Whether to replace current history entry.
|
|
189
|
+
* @property {unknown} [state]
|
|
190
|
+
* History state to pass.
|
|
42
191
|
* @description Object describing a navigation target for `router.navigate()`.
|
|
43
192
|
*/
|
|
44
193
|
|
|
45
194
|
/**
|
|
195
|
+
* Saved scroll position.
|
|
46
196
|
* @typedef {Object} ScrollPosition
|
|
47
|
-
* @property {number} x
|
|
48
|
-
*
|
|
197
|
+
* @property {number} x
|
|
198
|
+
* Horizontal scroll position.
|
|
199
|
+
* @property {number} y
|
|
200
|
+
* Vertical scroll position.
|
|
49
201
|
* @description Represents a saved scroll position.
|
|
50
202
|
*/
|
|
51
203
|
|
|
52
204
|
/**
|
|
205
|
+
* Internal representation of a parsed route path segment.
|
|
53
206
|
* @typedef {Object} RouteSegment
|
|
54
|
-
* @property {'static' | 'param'} type
|
|
55
|
-
*
|
|
56
|
-
* @property {string} [
|
|
207
|
+
* @property {'static' | 'param'} type
|
|
208
|
+
* The segment type.
|
|
209
|
+
* @property {string} [value]
|
|
210
|
+
* The segment value (static segments).
|
|
211
|
+
* @property {string} [name]
|
|
212
|
+
* The parameter name (param segments).
|
|
57
213
|
* @description Internal representation of a parsed route path segment.
|
|
58
214
|
* @private
|
|
59
215
|
*/
|
|
60
216
|
|
|
61
217
|
/**
|
|
218
|
+
* Result of matching a path against route definitions.
|
|
62
219
|
* @typedef {Object} RouteMatch
|
|
63
|
-
* @property {RouteDefinition} route
|
|
64
|
-
*
|
|
220
|
+
* @property {RouteDefinition} route
|
|
221
|
+
* The matched route definition.
|
|
222
|
+
* @property {RouteParams} params
|
|
223
|
+
* The extracted route parameters.
|
|
65
224
|
* @description Result of matching a path against route definitions.
|
|
66
225
|
* @private
|
|
67
226
|
*/
|
|
68
227
|
|
|
69
228
|
/**
|
|
70
|
-
*
|
|
71
|
-
* @
|
|
72
|
-
* Common properties include:
|
|
229
|
+
* Arbitrary metadata attached to routes for use in guards and components.
|
|
230
|
+
* @typedef {Record<string, unknown>} RouteMeta
|
|
231
|
+
* @description Common properties include:
|
|
73
232
|
* - `requiresAuth: boolean` - Whether the route requires authentication
|
|
74
233
|
* - `title: string` - Page title for the route
|
|
75
234
|
* - `roles: string[]` - Required user roles
|
|
@@ -82,91 +241,136 @@
|
|
|
82
241
|
*/
|
|
83
242
|
|
|
84
243
|
/**
|
|
244
|
+
* Interface for the router's error handling system.
|
|
85
245
|
* @typedef {Object} RouterErrorHandler
|
|
86
|
-
* @property {(error: Error, context: string, details?: Record<string,
|
|
87
|
-
*
|
|
88
|
-
* @property {(message: string,
|
|
246
|
+
* @property {(error: Error, context: string, details?: Record<string, unknown>) => void} handle
|
|
247
|
+
* Throws a formatted error.
|
|
248
|
+
* @property {(message: string, details?: Record<string, unknown>) => void} warn
|
|
249
|
+
* Logs a warning.
|
|
250
|
+
* @property {(message: string, error: Error, details?: Record<string, unknown>) => void} log
|
|
251
|
+
* Logs an error without throwing.
|
|
89
252
|
* @description Interface for the router's error handling system.
|
|
90
253
|
*/
|
|
91
254
|
|
|
92
|
-
//
|
|
93
|
-
// Event Callback
|
|
94
|
-
//
|
|
255
|
+
// -----------------------------------------------------------------------------
|
|
256
|
+
// Event Callback Types
|
|
257
|
+
// -----------------------------------------------------------------------------
|
|
95
258
|
|
|
96
259
|
/**
|
|
260
|
+
* Callback for `router:beforeEach` event.
|
|
97
261
|
* @callback NavigationContextCallback
|
|
98
|
-
* @param {NavigationContext} context
|
|
262
|
+
* @param {NavigationContext} context
|
|
263
|
+
* The navigation context (can be modified to block/redirect).
|
|
99
264
|
* @returns {void | Promise<void>}
|
|
100
|
-
* @description
|
|
265
|
+
* @description Modify context to control navigation flow.
|
|
101
266
|
*/
|
|
102
267
|
|
|
103
268
|
/**
|
|
269
|
+
* Callback for `router:beforeResolve` and `router:afterResolve` events.
|
|
104
270
|
* @callback ResolveContextCallback
|
|
105
|
-
* @param {ResolveContext} context
|
|
271
|
+
* @param {ResolveContext} context
|
|
272
|
+
* The resolve context (can be modified to block/redirect).
|
|
106
273
|
* @returns {void | Promise<void>}
|
|
107
274
|
* @description Callback for `router:beforeResolve` and `router:afterResolve` events.
|
|
108
275
|
*/
|
|
109
276
|
|
|
110
277
|
/**
|
|
278
|
+
* Callback for `router:beforeRender` and `router:afterRender` events.
|
|
111
279
|
* @callback RenderContextCallback
|
|
112
|
-
* @param {RenderContext} context
|
|
280
|
+
* @param {RenderContext} context
|
|
281
|
+
* The render context.
|
|
113
282
|
* @returns {void | Promise<void>}
|
|
114
283
|
* @description Callback for `router:beforeRender` and `router:afterRender` events.
|
|
115
284
|
*/
|
|
116
285
|
|
|
117
286
|
/**
|
|
287
|
+
* Callback for `router:scroll` event.
|
|
118
288
|
* @callback ScrollContextCallback
|
|
119
|
-
* @param {ScrollContext} context
|
|
289
|
+
* @param {ScrollContext} context
|
|
290
|
+
* The scroll context with saved position info.
|
|
120
291
|
* @returns {void | Promise<void>}
|
|
121
|
-
* @description
|
|
292
|
+
* @description Use to implement custom scroll behavior.
|
|
122
293
|
*/
|
|
123
294
|
|
|
124
295
|
/**
|
|
296
|
+
* Callback for `router:afterEnter`, `router:afterLeave`, `router:afterEach` events.
|
|
125
297
|
* @callback RouteChangeCallback
|
|
126
|
-
* @param {RouteLocation} to
|
|
127
|
-
*
|
|
298
|
+
* @param {RouteLocation} to
|
|
299
|
+
* The target route location.
|
|
300
|
+
* @param {RouteLocation | null} from
|
|
301
|
+
* The source route location.
|
|
128
302
|
* @returns {void | Promise<void>}
|
|
129
303
|
* @description Callback for `router:afterEnter`, `router:afterLeave`, `router:afterEach` events.
|
|
130
304
|
*/
|
|
131
305
|
|
|
132
306
|
/**
|
|
307
|
+
* Router context injected into component setup as `ctx.router`.
|
|
308
|
+
* @typedef {Object} RouterContext
|
|
309
|
+
* @property {NavigateFunction} navigate
|
|
310
|
+
* Programmatic navigation function.
|
|
311
|
+
* @property {Signal<RouteLocation | null>} current
|
|
312
|
+
* Reactive signal for current route.
|
|
313
|
+
* @property {Signal<RouteLocation | null>} previous
|
|
314
|
+
* Reactive signal for previous route.
|
|
315
|
+
* @property {RouteParams} params
|
|
316
|
+
* Current route params (getter).
|
|
317
|
+
* @property {QueryParams} query
|
|
318
|
+
* Current route query (getter).
|
|
319
|
+
* @property {string} path
|
|
320
|
+
* Current route path (getter).
|
|
321
|
+
* @property {string} fullUrl
|
|
322
|
+
* Current routed URL string (getter).
|
|
323
|
+
* @property {RouteMeta} meta
|
|
324
|
+
* Current route meta (getter).
|
|
325
|
+
* @description Injected into component setup as `ctx.router`.
|
|
326
|
+
*/
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Callback for `router:error` event.
|
|
133
330
|
* @callback RouterErrorCallback
|
|
134
|
-
* @param {Error} error
|
|
135
|
-
*
|
|
136
|
-
* @param {RouteLocation
|
|
331
|
+
* @param {Error} error
|
|
332
|
+
* The error that occurred.
|
|
333
|
+
* @param {RouteLocation} [to]
|
|
334
|
+
* The target route (if available).
|
|
335
|
+
* @param {RouteLocation | null} [from]
|
|
336
|
+
* The source route (if available).
|
|
137
337
|
* @returns {void | Promise<void>}
|
|
138
|
-
* @description Callback for `router:
|
|
338
|
+
* @description Callback for `router:error` event.
|
|
139
339
|
*/
|
|
140
340
|
|
|
141
341
|
/**
|
|
342
|
+
* Callback for `router:ready` event.
|
|
142
343
|
* @callback RouterReadyCallback
|
|
143
|
-
* @param {Router} router
|
|
344
|
+
* @param {Router} router
|
|
345
|
+
* The router instance.
|
|
144
346
|
* @returns {void | Promise<void>}
|
|
145
347
|
* @description Callback for `router:ready` event.
|
|
146
348
|
*/
|
|
147
349
|
|
|
148
350
|
/**
|
|
351
|
+
* Callback for `router:routeAdded` event.
|
|
149
352
|
* @callback RouteAddedCallback
|
|
150
|
-
* @param {RouteDefinition} route
|
|
353
|
+
* @param {RouteDefinition} route
|
|
354
|
+
* The added route definition.
|
|
151
355
|
* @returns {void | Promise<void>}
|
|
152
356
|
* @description Callback for `router:routeAdded` event.
|
|
153
357
|
*/
|
|
154
358
|
|
|
155
359
|
/**
|
|
360
|
+
* Callback for `router:routeRemoved` event.
|
|
156
361
|
* @callback RouteRemovedCallback
|
|
157
|
-
* @param {RouteDefinition} route
|
|
362
|
+
* @param {RouteDefinition} route
|
|
363
|
+
* The removed route definition.
|
|
158
364
|
* @returns {void | Promise<void>}
|
|
159
365
|
* @description Callback for `router:routeRemoved` event.
|
|
160
366
|
*/
|
|
161
367
|
|
|
162
|
-
//
|
|
163
|
-
//
|
|
164
|
-
//
|
|
368
|
+
// ============================================================================
|
|
369
|
+
// CORE IMPLEMENTATION
|
|
370
|
+
// ============================================================================
|
|
165
371
|
|
|
166
372
|
/**
|
|
167
373
|
* Simple error handler for the core router.
|
|
168
|
-
* Can be overridden by error handling plugins.
|
|
169
|
-
* Provides consistent error formatting and logging for router operations.
|
|
170
374
|
* @private
|
|
171
375
|
*/
|
|
172
376
|
const CoreErrorHandler = {
|
|
@@ -174,7 +378,7 @@ const CoreErrorHandler = {
|
|
|
174
378
|
* Handles router errors with basic formatting.
|
|
175
379
|
* @param {Error} error - The error to handle.
|
|
176
380
|
* @param {string} context - The context where the error occurred.
|
|
177
|
-
* @param {
|
|
381
|
+
* @param {Record<string, unknown>} details - Additional error details.
|
|
178
382
|
* @throws {Error} The formatted error.
|
|
179
383
|
*/
|
|
180
384
|
handle(error, context, details = {}) {
|
|
@@ -193,7 +397,7 @@ const CoreErrorHandler = {
|
|
|
193
397
|
/**
|
|
194
398
|
* Logs a warning without throwing an error.
|
|
195
399
|
* @param {string} message - The warning message.
|
|
196
|
-
* @param {
|
|
400
|
+
* @param {Record<string, unknown>} details - Additional warning details.
|
|
197
401
|
*/
|
|
198
402
|
warn(message, details = {}) {
|
|
199
403
|
console.warn(`[ElevaRouter] ${message}`, details);
|
|
@@ -203,7 +407,7 @@ const CoreErrorHandler = {
|
|
|
203
407
|
* Logs an error without throwing.
|
|
204
408
|
* @param {string} message - The error message.
|
|
205
409
|
* @param {Error} error - The original error.
|
|
206
|
-
* @param {
|
|
410
|
+
* @param {Record<string, unknown>} details - Additional error details.
|
|
207
411
|
*/
|
|
208
412
|
log(message, error, details = {}) {
|
|
209
413
|
console.error(`[ElevaRouter] ${message}`, { error, details });
|
|
@@ -211,30 +415,41 @@ const CoreErrorHandler = {
|
|
|
211
415
|
};
|
|
212
416
|
|
|
213
417
|
/**
|
|
418
|
+
* Represents the current or target location in the router.
|
|
214
419
|
* @typedef {Object} RouteLocation
|
|
215
|
-
* @property {string} path
|
|
216
|
-
*
|
|
217
|
-
* @property {
|
|
218
|
-
*
|
|
219
|
-
* @property {
|
|
220
|
-
*
|
|
221
|
-
* @property {
|
|
420
|
+
* @property {string} path
|
|
421
|
+
* The path of the route (e.g., '/users/123').
|
|
422
|
+
* @property {QueryParams} query
|
|
423
|
+
* Query parameters as key-value pairs.
|
|
424
|
+
* @property {string} fullUrl
|
|
425
|
+
* The routed URL string (path plus query).
|
|
426
|
+
* @property {RouteParams} params
|
|
427
|
+
* Dynamic route parameters.
|
|
428
|
+
* @property {RouteMeta} meta
|
|
429
|
+
* Metadata associated with the matched route.
|
|
430
|
+
* @property {string} [name]
|
|
431
|
+
* The optional name of the matched route.
|
|
432
|
+
* @property {RouteDefinition} matched
|
|
433
|
+
* The raw route definition that was matched.
|
|
222
434
|
* @description Represents the current or target location in the router.
|
|
223
435
|
*/
|
|
224
436
|
|
|
225
437
|
/**
|
|
226
|
-
*
|
|
227
|
-
* The return value of a navigation guard.
|
|
438
|
+
* Return value of a navigation guard.
|
|
228
439
|
* - `true` or `undefined/void`: Allow navigation
|
|
229
440
|
* - `false`: Abort navigation
|
|
230
441
|
* - `string`: Redirect to path
|
|
231
442
|
* - `NavigationTarget`: Redirect with options
|
|
443
|
+
* @typedef {boolean | string | NavigationTarget | void} NavigationGuardResult
|
|
232
444
|
*/
|
|
233
445
|
|
|
234
446
|
/**
|
|
447
|
+
* Navigation guard function that controls navigation flow.
|
|
235
448
|
* @callback NavigationGuard
|
|
236
|
-
* @param {RouteLocation} to
|
|
237
|
-
*
|
|
449
|
+
* @param {RouteLocation} to
|
|
450
|
+
* The target route location.
|
|
451
|
+
* @param {RouteLocation | null} from
|
|
452
|
+
* The source route location (null on initial).
|
|
238
453
|
* @returns {NavigationGuardResult | Promise<NavigationGuardResult>}
|
|
239
454
|
* @description A function that controls navigation flow. Runs before navigation is confirmed.
|
|
240
455
|
* @example
|
|
@@ -248,9 +463,12 @@ const CoreErrorHandler = {
|
|
|
248
463
|
*/
|
|
249
464
|
|
|
250
465
|
/**
|
|
466
|
+
* Navigation hook for side effects. Does not affect navigation flow.
|
|
251
467
|
* @callback NavigationHook
|
|
252
|
-
* @param {RouteLocation} to
|
|
253
|
-
*
|
|
468
|
+
* @param {RouteLocation} to
|
|
469
|
+
* The target route location.
|
|
470
|
+
* @param {RouteLocation | null} from
|
|
471
|
+
* The source route location.
|
|
254
472
|
* @returns {void | Promise<void>}
|
|
255
473
|
* @description A lifecycle hook for side effects. Does not affect navigation flow.
|
|
256
474
|
* @example
|
|
@@ -261,11 +479,16 @@ const CoreErrorHandler = {
|
|
|
261
479
|
*/
|
|
262
480
|
|
|
263
481
|
/**
|
|
482
|
+
* Interface for router plugins.
|
|
264
483
|
* @typedef {Object} RouterPlugin
|
|
265
|
-
* @property {string} name
|
|
266
|
-
*
|
|
267
|
-
* @property {
|
|
268
|
-
*
|
|
484
|
+
* @property {string} name
|
|
485
|
+
* Unique plugin identifier.
|
|
486
|
+
* @property {string} [version]
|
|
487
|
+
* Plugin version (recommended to match router version).
|
|
488
|
+
* @property {(router: Router, options?: Record<string, unknown>) => void} install
|
|
489
|
+
* Installation function.
|
|
490
|
+
* @property {(router: Router) => void | Promise<void>} [destroy]
|
|
491
|
+
* Cleanup function called on router.destroy().
|
|
269
492
|
* @description Interface for router plugins. Plugins can extend router functionality.
|
|
270
493
|
* @example
|
|
271
494
|
* const AnalyticsPlugin = {
|
|
@@ -280,67 +503,103 @@ const CoreErrorHandler = {
|
|
|
280
503
|
*/
|
|
281
504
|
|
|
282
505
|
/**
|
|
506
|
+
* Context object for navigation events that plugins can modify.
|
|
283
507
|
* @typedef {Object} NavigationContext
|
|
284
|
-
* @property {RouteLocation} to
|
|
285
|
-
*
|
|
286
|
-
* @property {
|
|
287
|
-
*
|
|
288
|
-
* @
|
|
508
|
+
* @property {RouteLocation} to
|
|
509
|
+
* The target route location.
|
|
510
|
+
* @property {RouteLocation | null} from
|
|
511
|
+
* The source route location.
|
|
512
|
+
* @property {boolean} cancelled
|
|
513
|
+
* Whether navigation has been cancelled.
|
|
514
|
+
* @property {string | NavigationTarget | null} redirectTo
|
|
515
|
+
* Redirect target if set.
|
|
516
|
+
* @description Passed to navigation events. Plugins can modify to control navigation flow.
|
|
289
517
|
*/
|
|
290
518
|
|
|
291
519
|
/**
|
|
520
|
+
* Context object for component resolution events.
|
|
292
521
|
* @typedef {Object} ResolveContext
|
|
293
|
-
* @property {RouteLocation} to
|
|
294
|
-
*
|
|
295
|
-
* @property {
|
|
296
|
-
*
|
|
297
|
-
* @property {
|
|
298
|
-
*
|
|
299
|
-
* @property {
|
|
300
|
-
*
|
|
522
|
+
* @property {RouteLocation} to
|
|
523
|
+
* The target route location.
|
|
524
|
+
* @property {RouteLocation | null} from
|
|
525
|
+
* The source route location.
|
|
526
|
+
* @property {RouteDefinition} route
|
|
527
|
+
* The matched route definition.
|
|
528
|
+
* @property {ComponentDefinition | null} layoutComponent
|
|
529
|
+
* The resolved layout component (available in afterResolve).
|
|
530
|
+
* @property {ComponentDefinition | null} pageComponent
|
|
531
|
+
* The resolved page component (available in afterResolve).
|
|
532
|
+
* @property {boolean} cancelled
|
|
533
|
+
* Whether navigation has been cancelled.
|
|
534
|
+
* @property {string | NavigationTarget | null} redirectTo
|
|
535
|
+
* Redirect target if set.
|
|
536
|
+
* @description Passed to component resolution events.
|
|
301
537
|
*/
|
|
302
538
|
|
|
303
539
|
/**
|
|
540
|
+
* Context object for render events.
|
|
304
541
|
* @typedef {Object} RenderContext
|
|
305
|
-
* @property {RouteLocation} to
|
|
306
|
-
*
|
|
307
|
-
* @property {
|
|
308
|
-
*
|
|
309
|
-
* @
|
|
542
|
+
* @property {RouteLocation} to
|
|
543
|
+
* The target route location.
|
|
544
|
+
* @property {RouteLocation | null} from
|
|
545
|
+
* The source route location.
|
|
546
|
+
* @property {ComponentDefinition | null} layoutComponent
|
|
547
|
+
* The layout component being rendered.
|
|
548
|
+
* @property {ComponentDefinition} pageComponent
|
|
549
|
+
* The page component being rendered.
|
|
550
|
+
* @description Passed to render events.
|
|
310
551
|
*/
|
|
311
552
|
|
|
312
553
|
/**
|
|
554
|
+
* Context object for scroll events.
|
|
313
555
|
* @typedef {Object} ScrollContext
|
|
314
|
-
* @property {RouteLocation} to
|
|
315
|
-
*
|
|
316
|
-
* @property {
|
|
317
|
-
*
|
|
556
|
+
* @property {RouteLocation} to
|
|
557
|
+
* The target route location.
|
|
558
|
+
* @property {RouteLocation | null} from
|
|
559
|
+
* The source route location.
|
|
560
|
+
* @property {{x: number, y: number} | null} savedPosition
|
|
561
|
+
* Saved position (back/forward nav).
|
|
562
|
+
* @description Passed to scroll events for plugins to handle scroll behavior.
|
|
318
563
|
*/
|
|
319
564
|
|
|
320
565
|
/**
|
|
321
|
-
* @typedef {string | ComponentDefinition | (() => Promise<{default: ComponentDefinition}>)} RouteComponent
|
|
322
566
|
* A component that can be rendered for a route.
|
|
323
567
|
* - `string`: Name of a registered component
|
|
324
568
|
* - `ComponentDefinition`: Inline component definition
|
|
325
|
-
* - `() =>
|
|
569
|
+
* - `() => ComponentDefinition`: Factory function returning a component
|
|
570
|
+
* - `() => Promise<ComponentDefinition>`: Async factory function
|
|
571
|
+
* - `() => Promise<{default: ComponentDefinition}>`: Lazy-loaded module (e.g., `() => import('./Page.js')`)
|
|
572
|
+
* @typedef {string | ComponentDefinition | (() => ComponentDefinition | Promise<ComponentDefinition | {default: ComponentDefinition}>)} RouteComponent
|
|
326
573
|
*/
|
|
327
574
|
|
|
328
575
|
/**
|
|
576
|
+
* Defines a route in the application.
|
|
329
577
|
* @typedef {Object} RouteDefinition
|
|
330
|
-
* @property {string} path
|
|
331
|
-
*
|
|
332
|
-
*
|
|
333
|
-
*
|
|
334
|
-
*
|
|
335
|
-
* @property {RouteComponent}
|
|
336
|
-
*
|
|
337
|
-
* @property {
|
|
338
|
-
*
|
|
339
|
-
* @property {
|
|
340
|
-
*
|
|
341
|
-
* @property {
|
|
342
|
-
*
|
|
578
|
+
* @property {string} path
|
|
579
|
+
* URL path pattern. Supports:
|
|
580
|
+
* - Static: '/about'
|
|
581
|
+
* - Dynamic params: '/users/:id'
|
|
582
|
+
* - Wildcard: '*' (catch-all, conventionally last)
|
|
583
|
+
* @property {RouteComponent} component
|
|
584
|
+
* The component to render for this route.
|
|
585
|
+
* @property {RouteComponent} [layout]
|
|
586
|
+
* Optional layout component to wrap the route component.
|
|
587
|
+
* @property {string} [name]
|
|
588
|
+
* Optional route name for programmatic navigation.
|
|
589
|
+
* @property {RouteMeta} [meta]
|
|
590
|
+
* Optional metadata (auth flags, titles, etc.).
|
|
591
|
+
* @property {NavigationGuard} [beforeEnter]
|
|
592
|
+
* Route-specific guard before entering.
|
|
593
|
+
* @property {NavigationHook} [afterEnter]
|
|
594
|
+
* Hook after entering and component is mounted.
|
|
595
|
+
* @property {NavigationGuard} [beforeLeave]
|
|
596
|
+
* Guard before leaving this route.
|
|
597
|
+
* @property {NavigationHook} [afterLeave]
|
|
598
|
+
* Hook after leaving and component is unmounted.
|
|
599
|
+
* @property {RouteSegment[]} [segments]
|
|
600
|
+
* Internal: parsed path segments (added by router).
|
|
343
601
|
* @description Defines a route in the application.
|
|
602
|
+
* @note Nested routes are not supported. Use shared layouts with flat routes instead.
|
|
344
603
|
* @example
|
|
345
604
|
* // Static route
|
|
346
605
|
* { path: '/about', component: AboutPage }
|
|
@@ -356,12 +615,12 @@ const CoreErrorHandler = {
|
|
|
356
615
|
* beforeEnter: (to, from) => isLoggedIn() || '/login'
|
|
357
616
|
* }
|
|
358
617
|
*
|
|
359
|
-
* // Catch-all 404 route (
|
|
618
|
+
* // Catch-all 404 route (conventionally last)
|
|
360
619
|
* { path: '*', component: NotFoundPage }
|
|
361
620
|
*/
|
|
362
621
|
|
|
363
622
|
/**
|
|
364
|
-
* @class Router
|
|
623
|
+
* @class 🛤️ Router
|
|
365
624
|
* @classdesc A powerful, reactive, and flexible Router Plugin for Eleva.
|
|
366
625
|
* This class manages all routing logic, including state, navigation, and rendering.
|
|
367
626
|
*
|
|
@@ -387,15 +646,15 @@ const CoreErrorHandler = {
|
|
|
387
646
|
* | `router:scroll` | {@link ScrollContextCallback} | No | For scroll behavior |
|
|
388
647
|
* | `router:afterEnter` | {@link RouteChangeCallback} | No | After entering route |
|
|
389
648
|
* | `router:afterEach` | {@link RouteChangeCallback} | No | Navigation complete |
|
|
390
|
-
* | `router:
|
|
649
|
+
* | `router:error` | {@link RouterErrorCallback} | No | Navigation error |
|
|
391
650
|
* | `router:routeAdded` | {@link RouteAddedCallback} | No | Dynamic route added |
|
|
392
651
|
* | `router:routeRemoved` | {@link RouteRemovedCallback} | No | Dynamic route removed |
|
|
393
652
|
*
|
|
394
653
|
* ## Reactive Signals
|
|
395
654
|
* - `currentRoute: Signal<RouteLocation | null>` - Current route info
|
|
396
655
|
* - `previousRoute: Signal<RouteLocation | null>` - Previous route info
|
|
397
|
-
* - `currentParams: Signal<
|
|
398
|
-
* - `currentQuery: Signal<
|
|
656
|
+
* - `currentParams: Signal<RouteParams>` - Current route params
|
|
657
|
+
* - `currentQuery: Signal<QueryParams>` - Current query params
|
|
399
658
|
* - `currentLayout: Signal<MountResult | null>` - Mounted layout instance
|
|
400
659
|
* - `currentView: Signal<MountResult | null>` - Mounted view instance
|
|
401
660
|
* - `isReady: Signal<boolean>` - Router readiness state
|
|
@@ -436,6 +695,7 @@ class Router {
|
|
|
436
695
|
* Creates an instance of the Router.
|
|
437
696
|
* @param {Eleva} eleva - The Eleva framework instance.
|
|
438
697
|
* @param {RouterOptions} options - The configuration options for the router.
|
|
698
|
+
* @throws {Error} If the routing mode is invalid.
|
|
439
699
|
*/
|
|
440
700
|
constructor(eleva, options = {}) {
|
|
441
701
|
/** @type {Eleva} The Eleva framework instance. */
|
|
@@ -452,7 +712,7 @@ class Router {
|
|
|
452
712
|
/** @private @type {RouteDefinition[]} The processed list of route definitions. */
|
|
453
713
|
this.routes = this._processRoutes(options.routes || []);
|
|
454
714
|
|
|
455
|
-
/** @private @type {
|
|
715
|
+
/** @private @type {Emitter} The shared Eleva event emitter for global hooks. */
|
|
456
716
|
this.emitter = this.eleva.emitter;
|
|
457
717
|
|
|
458
718
|
/** @private @type {boolean} A flag indicating if the router has been started. */
|
|
@@ -464,7 +724,7 @@ class Router {
|
|
|
464
724
|
/** @private @type {number} Counter for tracking navigation operations to prevent race conditions. */
|
|
465
725
|
this._navigationId = 0;
|
|
466
726
|
|
|
467
|
-
/** @private @type {
|
|
727
|
+
/** @private @type {UnsubscribeFunction[]} A collection of cleanup functions for event listeners. */
|
|
468
728
|
this.eventListeners = [];
|
|
469
729
|
|
|
470
730
|
/** @type {Signal<RouteLocation | null>} A reactive signal holding the current route's information. */
|
|
@@ -473,16 +733,16 @@ class Router {
|
|
|
473
733
|
/** @type {Signal<RouteLocation | null>} A reactive signal holding the previous route's information. */
|
|
474
734
|
this.previousRoute = new this.eleva.signal(null);
|
|
475
735
|
|
|
476
|
-
/** @type {Signal<
|
|
736
|
+
/** @type {Signal<RouteParams>} A reactive signal holding the current route's parameters. */
|
|
477
737
|
this.currentParams = new this.eleva.signal({});
|
|
478
738
|
|
|
479
|
-
/** @type {Signal<
|
|
739
|
+
/** @type {Signal<QueryParams>} A reactive signal holding the current route's query parameters. */
|
|
480
740
|
this.currentQuery = new this.eleva.signal({});
|
|
481
741
|
|
|
482
|
-
/** @type {Signal<
|
|
742
|
+
/** @type {Signal<MountResult | null>} A reactive signal for the currently mounted layout instance. */
|
|
483
743
|
this.currentLayout = new this.eleva.signal(null);
|
|
484
744
|
|
|
485
|
-
/** @type {Signal<
|
|
745
|
+
/** @type {Signal<MountResult | null>} A reactive signal for the currently mounted view (page) instance. */
|
|
486
746
|
this.currentView = new this.eleva.signal(null);
|
|
487
747
|
|
|
488
748
|
/** @type {Signal<boolean>} A reactive signal indicating if the router is ready (started and initial navigation complete). */
|
|
@@ -491,7 +751,7 @@ class Router {
|
|
|
491
751
|
/** @private @type {Map<string, RouterPlugin>} Map of registered plugins by name. */
|
|
492
752
|
this.plugins = new Map();
|
|
493
753
|
|
|
494
|
-
/** @private @type {
|
|
754
|
+
/** @private @type {NavigationGuard[]} Array of global before-each navigation guards. */
|
|
495
755
|
this._beforeEachGuards = [];
|
|
496
756
|
|
|
497
757
|
// If onBeforeEach was provided in options, add it to the guards array
|
|
@@ -499,7 +759,7 @@ class Router {
|
|
|
499
759
|
this._beforeEachGuards.push(options.onBeforeEach);
|
|
500
760
|
}
|
|
501
761
|
|
|
502
|
-
/** @type {
|
|
762
|
+
/** @type {RouterErrorHandler} The error handler instance. Can be overridden by plugins. */
|
|
503
763
|
this.errorHandler = CoreErrorHandler;
|
|
504
764
|
|
|
505
765
|
/** @private @type {Map<string, {x: number, y: number}>} Saved scroll positions by route path. */
|
|
@@ -552,7 +812,7 @@ class Router {
|
|
|
552
812
|
* Parses a route path string into an array of static and parameter segments.
|
|
553
813
|
* @private
|
|
554
814
|
* @param {string} path - The path pattern to parse.
|
|
555
|
-
* @returns {
|
|
815
|
+
* @returns {{type: 'static' | 'param', value?: string, name?: string}[]} An array of segment objects.
|
|
556
816
|
* @throws {Error} If the route path is not a valid string.
|
|
557
817
|
*/
|
|
558
818
|
_parsePathIntoSegments(path) {
|
|
@@ -609,6 +869,11 @@ class Router {
|
|
|
609
869
|
/**
|
|
610
870
|
* Starts the router, initializes event listeners, and performs the initial navigation.
|
|
611
871
|
* @returns {Promise<Router>} The router instance for method chaining.
|
|
872
|
+
* @listens window:hashchange In hash mode, triggers route changes.
|
|
873
|
+
* @listens window:popstate In history/query mode, triggers route changes.
|
|
874
|
+
* @emits router:ready When initialization completes successfully.
|
|
875
|
+
* @see destroy - Stop the router and clean up listeners.
|
|
876
|
+
* @see navigate - Programmatically navigate to a route.
|
|
612
877
|
*
|
|
613
878
|
* @example
|
|
614
879
|
* // Basic usage
|
|
@@ -665,8 +930,11 @@ class Router {
|
|
|
665
930
|
}
|
|
666
931
|
|
|
667
932
|
/**
|
|
668
|
-
* Stops the router and cleans up
|
|
933
|
+
* Stops the router and cleans up event listeners.
|
|
934
|
+
* Unmounts the current layout instance if present.
|
|
935
|
+
* @async
|
|
669
936
|
* @returns {Promise<void>}
|
|
937
|
+
* @see start - Restart the router after destroying.
|
|
670
938
|
*/
|
|
671
939
|
async destroy() {
|
|
672
940
|
if (!this.isStarted) return;
|
|
@@ -694,6 +962,7 @@ class Router {
|
|
|
694
962
|
/**
|
|
695
963
|
* Alias for destroy(). Stops the router and cleans up all resources.
|
|
696
964
|
* Provided for semantic consistency (start/stop pattern).
|
|
965
|
+
* @async
|
|
697
966
|
* @returns {Promise<void>}
|
|
698
967
|
*
|
|
699
968
|
* @example
|
|
@@ -707,9 +976,13 @@ class Router {
|
|
|
707
976
|
|
|
708
977
|
/**
|
|
709
978
|
* Programmatically navigates to a new route.
|
|
979
|
+
* @async
|
|
710
980
|
* @param {string | NavigationTarget} location - The target location as a path string or navigation target object.
|
|
711
|
-
* @param {
|
|
981
|
+
* @param {NavigationParams} [params] - Route parameters (only used when location is a string).
|
|
712
982
|
* @returns {Promise<boolean>} True if navigation succeeded, false if blocked by guards or failed.
|
|
983
|
+
* @emits router:error When navigation fails due to an exception.
|
|
984
|
+
* @see start - Initialize the router before navigating.
|
|
985
|
+
* @see currentRoute - Access the current route after navigation.
|
|
713
986
|
*
|
|
714
987
|
* @example
|
|
715
988
|
* // Basic navigation
|
|
@@ -780,7 +1053,7 @@ class Router {
|
|
|
780
1053
|
return navigationSuccessful;
|
|
781
1054
|
} catch (error) {
|
|
782
1055
|
this.errorHandler.log("Navigation failed", error);
|
|
783
|
-
await this.emitter.emit("router:
|
|
1056
|
+
await this.emitter.emit("router:error", error);
|
|
784
1057
|
return false;
|
|
785
1058
|
}
|
|
786
1059
|
}
|
|
@@ -803,7 +1076,7 @@ class Router {
|
|
|
803
1076
|
* @param {string} path - The target path with query string.
|
|
804
1077
|
* @param {object} params - The target params.
|
|
805
1078
|
* @param {object} query - The target query.
|
|
806
|
-
* @returns {boolean}
|
|
1079
|
+
* @returns {boolean} True if the routes are the same.
|
|
807
1080
|
*/
|
|
808
1081
|
_isSameRoute(path, params, query) {
|
|
809
1082
|
const current = this.currentRoute.value;
|
|
@@ -819,7 +1092,16 @@ class Router {
|
|
|
819
1092
|
|
|
820
1093
|
/**
|
|
821
1094
|
* Injects dynamic parameters into a path string.
|
|
1095
|
+
* Replaces `:param` placeholders with URL-encoded values from the params object.
|
|
1096
|
+
*
|
|
822
1097
|
* @private
|
|
1098
|
+
* @param {string} path - The path pattern containing `:param` placeholders.
|
|
1099
|
+
* @param {RouteParams} params - Key-value pairs to inject into the path.
|
|
1100
|
+
* @returns {string} The path with all parameters replaced.
|
|
1101
|
+
*
|
|
1102
|
+
* @example
|
|
1103
|
+
* this._buildPath('/users/:id/posts/:postId', { id: '123', postId: '456' });
|
|
1104
|
+
* // Returns: '/users/123/posts/456'
|
|
823
1105
|
*/
|
|
824
1106
|
_buildPath(path, params) {
|
|
825
1107
|
let result = path;
|
|
@@ -833,8 +1115,12 @@ class Router {
|
|
|
833
1115
|
|
|
834
1116
|
/**
|
|
835
1117
|
* The handler for browser-initiated route changes (e.g., back/forward buttons).
|
|
1118
|
+
*
|
|
836
1119
|
* @private
|
|
1120
|
+
* @async
|
|
837
1121
|
* @param {boolean} [isPopState=true] - Whether this is a popstate event (back/forward navigation).
|
|
1122
|
+
* @returns {Promise<void>}
|
|
1123
|
+
* @emits router:error When route change handling fails.
|
|
838
1124
|
*/
|
|
839
1125
|
async _handleRouteChange(isPopState = true) {
|
|
840
1126
|
if (this._isNavigating) return;
|
|
@@ -856,27 +1142,31 @@ class Router {
|
|
|
856
1142
|
this.errorHandler.log("Route change handling failed", error, {
|
|
857
1143
|
currentUrl: typeof window !== "undefined" ? window.location.href : "",
|
|
858
1144
|
});
|
|
859
|
-
await this.emitter.emit("router:
|
|
1145
|
+
await this.emitter.emit("router:error", error);
|
|
860
1146
|
}
|
|
861
1147
|
}
|
|
862
1148
|
|
|
863
1149
|
/**
|
|
864
1150
|
* Manages the core navigation lifecycle. Runs guards before committing changes.
|
|
865
|
-
* Emits lifecycle events that plugins can hook into:
|
|
866
|
-
* - router:beforeEach - Before guards run (can block/redirect via context)
|
|
867
|
-
* - router:beforeResolve - Before component resolution (can block/redirect)
|
|
868
|
-
* - router:afterResolve - After components are resolved
|
|
869
|
-
* - router:beforeRender - Before DOM rendering
|
|
870
|
-
* - router:afterRender - After DOM rendering
|
|
871
|
-
* - router:scroll - After render, for scroll behavior
|
|
872
|
-
* - router:afterEnter - After entering a route
|
|
873
|
-
* - router:afterLeave - After leaving a route
|
|
874
|
-
* - router:afterEach - After navigation completes
|
|
875
1151
|
*
|
|
876
1152
|
* @private
|
|
1153
|
+
* @async
|
|
877
1154
|
* @param {string} fullPath - The full path (e.g., '/users/123?foo=bar') to navigate to.
|
|
878
1155
|
* @param {boolean} [isPopState=false] - Whether this navigation was triggered by popstate (back/forward).
|
|
879
|
-
* @returns {Promise<boolean>}
|
|
1156
|
+
* @returns {Promise<boolean>} `true` if navigation succeeded, `false` if aborted.
|
|
1157
|
+
* @emits router:notFound When no matching route is found.
|
|
1158
|
+
* @emits router:beforeResolve Before component resolution (can block/redirect).
|
|
1159
|
+
* @emits router:afterResolve After components are resolved.
|
|
1160
|
+
* @emits router:afterLeave After leaving the previous route.
|
|
1161
|
+
* @emits router:beforeRender Before DOM rendering.
|
|
1162
|
+
* @emits router:afterRender After DOM rendering completes.
|
|
1163
|
+
* @emits router:scroll After render, for scroll behavior handling.
|
|
1164
|
+
* @emits router:afterEnter After entering the new route.
|
|
1165
|
+
* @emits router:afterEach After navigation completes successfully.
|
|
1166
|
+
* @emits router:error When an error occurs during navigation.
|
|
1167
|
+
* @see _runGuards - Guard execution.
|
|
1168
|
+
* @see _resolveComponents - Component resolution.
|
|
1169
|
+
* @see _render - DOM rendering.
|
|
880
1170
|
*/
|
|
881
1171
|
async _proceedWithNavigation(fullPath, isPopState = false) {
|
|
882
1172
|
const from = this.currentRoute.value;
|
|
@@ -900,7 +1190,7 @@ class Router {
|
|
|
900
1190
|
};
|
|
901
1191
|
} else {
|
|
902
1192
|
await this.emitter.emit(
|
|
903
|
-
"router:
|
|
1193
|
+
"router:error",
|
|
904
1194
|
new Error(`Route not found: ${toLocation.path}`),
|
|
905
1195
|
toLocation,
|
|
906
1196
|
from
|
|
@@ -1010,7 +1300,7 @@ class Router {
|
|
|
1010
1300
|
await this.emitter.emit("router:beforeRender", renderContext);
|
|
1011
1301
|
|
|
1012
1302
|
// 9. Render the new components.
|
|
1013
|
-
await this._render(layoutComponent, pageComponent
|
|
1303
|
+
await this._render(layoutComponent, pageComponent);
|
|
1014
1304
|
|
|
1015
1305
|
// 10. Emit afterRender event - plugins can trigger animations
|
|
1016
1306
|
await this.emitter.emit("router:afterRender", renderContext);
|
|
@@ -1036,7 +1326,7 @@ class Router {
|
|
|
1036
1326
|
return true;
|
|
1037
1327
|
} catch (error) {
|
|
1038
1328
|
this.errorHandler.log("Error during navigation", error, { to, from });
|
|
1039
|
-
await this.emitter.emit("router:
|
|
1329
|
+
await this.emitter.emit("router:error", error, to, from);
|
|
1040
1330
|
return false;
|
|
1041
1331
|
}
|
|
1042
1332
|
}
|
|
@@ -1053,7 +1343,8 @@ class Router {
|
|
|
1053
1343
|
* @param {RouteLocation} to - The target route location.
|
|
1054
1344
|
* @param {RouteLocation | null} from - The current route location (null on initial navigation).
|
|
1055
1345
|
* @param {RouteDefinition} route - The matched route definition.
|
|
1056
|
-
* @returns {Promise<boolean>}
|
|
1346
|
+
* @returns {Promise<boolean>} `false` if navigation should be aborted.
|
|
1347
|
+
* @emits router:beforeEach Before guards run (can block/redirect via context).
|
|
1057
1348
|
*/
|
|
1058
1349
|
async _runGuards(to, from, route) {
|
|
1059
1350
|
// Create navigation context that plugins can modify to block navigation
|
|
@@ -1123,7 +1414,8 @@ class Router {
|
|
|
1123
1414
|
/**
|
|
1124
1415
|
* Resolves a function component definition to a component object.
|
|
1125
1416
|
* @private
|
|
1126
|
-
* @
|
|
1417
|
+
* @async
|
|
1418
|
+
* @param {() => ComponentDefinition | Promise<ComponentDefinition | { default: ComponentDefinition }>} def - The function to resolve.
|
|
1127
1419
|
* @returns {Promise<ComponentDefinition>} The resolved component.
|
|
1128
1420
|
* @throws {Error} If the function fails to load the component.
|
|
1129
1421
|
*/
|
|
@@ -1147,7 +1439,7 @@ class Router {
|
|
|
1147
1439
|
/**
|
|
1148
1440
|
* Validates a component definition object.
|
|
1149
1441
|
* @private
|
|
1150
|
-
* @param {
|
|
1442
|
+
* @param {unknown} def - The component definition to validate.
|
|
1151
1443
|
* @returns {ComponentDefinition} The validated component.
|
|
1152
1444
|
* @throws {Error} If the component definition is invalid.
|
|
1153
1445
|
*/
|
|
@@ -1177,7 +1469,7 @@ class Router {
|
|
|
1177
1469
|
/**
|
|
1178
1470
|
* Resolves a component definition to a component object.
|
|
1179
1471
|
* @private
|
|
1180
|
-
* @param {
|
|
1472
|
+
* @param {unknown} def - The component definition to resolve.
|
|
1181
1473
|
* @returns {Promise<ComponentDefinition | null>} The resolved component or null.
|
|
1182
1474
|
*/
|
|
1183
1475
|
async _resolveComponent(def) {
|
|
@@ -1207,8 +1499,10 @@ class Router {
|
|
|
1207
1499
|
/**
|
|
1208
1500
|
* Asynchronously resolves the layout and page components for a route.
|
|
1209
1501
|
* @private
|
|
1502
|
+
* @async
|
|
1210
1503
|
* @param {RouteDefinition} route - The route to resolve components for.
|
|
1211
1504
|
* @returns {Promise<{layoutComponent: ComponentDefinition | null, pageComponent: ComponentDefinition}>}
|
|
1505
|
+
* @throws {Error} If page component cannot be resolved.
|
|
1212
1506
|
*/
|
|
1213
1507
|
async _resolveComponents(route) {
|
|
1214
1508
|
const effectiveLayout = route.layout || this.options.globalLayout;
|
|
@@ -1242,9 +1536,24 @@ class Router {
|
|
|
1242
1536
|
|
|
1243
1537
|
/**
|
|
1244
1538
|
* Renders the components for the current route into the DOM.
|
|
1539
|
+
*
|
|
1540
|
+
* Rendering algorithm:
|
|
1541
|
+
* 1. Find the mount element using options.mount selector
|
|
1542
|
+
* 2. If layoutComponent exists:
|
|
1543
|
+
* a. Mount layout to mount element
|
|
1544
|
+
* b. Find view element within layout (using viewSelector)
|
|
1545
|
+
* c. Mount page component to view element
|
|
1546
|
+
* 3. If no layoutComponent:
|
|
1547
|
+
* a. Mount page component directly to mount element
|
|
1548
|
+
* b. Set currentLayout to null
|
|
1549
|
+
*
|
|
1245
1550
|
* @private
|
|
1551
|
+
* @async
|
|
1246
1552
|
* @param {ComponentDefinition | null} layoutComponent - The pre-loaded layout component.
|
|
1247
1553
|
* @param {ComponentDefinition} pageComponent - The pre-loaded page component.
|
|
1554
|
+
* @returns {Promise<void>}
|
|
1555
|
+
* @throws {Error} If mount element is not found in the DOM.
|
|
1556
|
+
* @throws {Error} If component mounting fails (propagated from eleva.mount).
|
|
1248
1557
|
*/
|
|
1249
1558
|
async _render(layoutComponent, pageComponent) {
|
|
1250
1559
|
const mountEl = document.querySelector(this.options.mount);
|
|
@@ -1281,8 +1590,8 @@ class Router {
|
|
|
1281
1590
|
* Creates a getter function for router context properties.
|
|
1282
1591
|
* @private
|
|
1283
1592
|
* @param {string} property - The property name to access.
|
|
1284
|
-
* @param {
|
|
1285
|
-
* @returns {
|
|
1593
|
+
* @param {unknown} defaultValue - The default value if property is undefined.
|
|
1594
|
+
* @returns {() => unknown} A getter function.
|
|
1286
1595
|
*/
|
|
1287
1596
|
_createRouteGetter(property, defaultValue) {
|
|
1288
1597
|
return () => this.currentRoute.value?.[property] ?? defaultValue;
|
|
@@ -1301,6 +1610,7 @@ class Router {
|
|
|
1301
1610
|
return {
|
|
1302
1611
|
...component,
|
|
1303
1612
|
async setup(ctx) {
|
|
1613
|
+
/** @type {RouterContext} */
|
|
1304
1614
|
ctx.router = {
|
|
1305
1615
|
navigate: self.navigate.bind(self),
|
|
1306
1616
|
current: self.currentRoute,
|
|
@@ -1331,9 +1641,13 @@ class Router {
|
|
|
1331
1641
|
|
|
1332
1642
|
/**
|
|
1333
1643
|
* Recursively wraps all child components to ensure they have access to router context.
|
|
1644
|
+
* String component references are returned as-is (context injected during mount).
|
|
1645
|
+
* Objects are wrapped with router context and their children are recursively wrapped.
|
|
1646
|
+
*
|
|
1334
1647
|
* @private
|
|
1335
1648
|
* @param {ComponentDefinition | string} component - The component to wrap (can be a definition object or a registered component name).
|
|
1336
1649
|
* @returns {ComponentDefinition | string} The wrapped component definition or the original string reference.
|
|
1650
|
+
* @see _wrapComponent - Single component wrapping.
|
|
1337
1651
|
*/
|
|
1338
1652
|
_wrapComponentWithChildren(component) {
|
|
1339
1653
|
// If the component is a string (registered component name), return as-is
|
|
@@ -1401,7 +1715,15 @@ class Router {
|
|
|
1401
1715
|
|
|
1402
1716
|
/**
|
|
1403
1717
|
* Parses a query string into a key-value object.
|
|
1718
|
+
* Uses URLSearchParams for robust parsing of encoded values.
|
|
1719
|
+
*
|
|
1404
1720
|
* @private
|
|
1721
|
+
* @param {string} queryString - The query string to parse (without leading '?').
|
|
1722
|
+
* @returns {QueryParams} Key-value pairs from the query string.
|
|
1723
|
+
*
|
|
1724
|
+
* @example
|
|
1725
|
+
* this._parseQuery('foo=bar&baz=qux');
|
|
1726
|
+
* // Returns: { foo: 'bar', baz: 'qux' }
|
|
1405
1727
|
*/
|
|
1406
1728
|
_parseQuery(queryString) {
|
|
1407
1729
|
const query = {};
|
|
@@ -1455,10 +1777,12 @@ class Router {
|
|
|
1455
1777
|
/**
|
|
1456
1778
|
* Adds a new route dynamically at runtime.
|
|
1457
1779
|
* The route will be processed and available for navigation immediately.
|
|
1780
|
+
* Routes are inserted before the wildcard (*) route if one exists.
|
|
1458
1781
|
*
|
|
1459
1782
|
* @param {RouteDefinition} route - The route definition to add.
|
|
1460
1783
|
* @param {RouteDefinition} [parentRoute] - Optional parent route to add as a child (not yet implemented).
|
|
1461
|
-
* @returns {() => void} A function to remove the added route.
|
|
1784
|
+
* @returns {() => void} A function to remove the added route (returns no-op if route was invalid).
|
|
1785
|
+
* @emits router:routeAdded When a route is successfully added.
|
|
1462
1786
|
*
|
|
1463
1787
|
* @example
|
|
1464
1788
|
* // Add a route dynamically
|
|
@@ -1511,6 +1835,7 @@ class Router {
|
|
|
1511
1835
|
*
|
|
1512
1836
|
* @param {string} path - The path of the route to remove.
|
|
1513
1837
|
* @returns {boolean} True if the route was removed, false if not found.
|
|
1838
|
+
* @emits router:routeRemoved When a route is successfully removed.
|
|
1514
1839
|
*
|
|
1515
1840
|
* @example
|
|
1516
1841
|
* router.removeRoute('/dynamic');
|
|
@@ -1609,6 +1934,7 @@ class Router {
|
|
|
1609
1934
|
* Registers a global hook that runs after a new route component has been mounted.
|
|
1610
1935
|
* @param {NavigationHook} hook - The hook function to register.
|
|
1611
1936
|
* @returns {() => void} A function to unregister the hook.
|
|
1937
|
+
* @listens router:afterEnter
|
|
1612
1938
|
*/
|
|
1613
1939
|
onAfterEnter(hook) {
|
|
1614
1940
|
return this.emitter.on("router:afterEnter", hook);
|
|
@@ -1618,6 +1944,7 @@ class Router {
|
|
|
1618
1944
|
* Registers a global hook that runs after a route component has been unmounted.
|
|
1619
1945
|
* @param {NavigationHook} hook - The hook function to register.
|
|
1620
1946
|
* @returns {() => void} A function to unregister the hook.
|
|
1947
|
+
* @listens router:afterLeave
|
|
1621
1948
|
*/
|
|
1622
1949
|
onAfterLeave(hook) {
|
|
1623
1950
|
return this.emitter.on("router:afterLeave", hook);
|
|
@@ -1627,6 +1954,7 @@ class Router {
|
|
|
1627
1954
|
* Registers a global hook that runs after a navigation has been confirmed and all hooks have completed.
|
|
1628
1955
|
* @param {NavigationHook} hook - The hook function to register.
|
|
1629
1956
|
* @returns {() => void} A function to unregister the hook.
|
|
1957
|
+
* @listens router:afterEach
|
|
1630
1958
|
*/
|
|
1631
1959
|
onAfterEach(hook) {
|
|
1632
1960
|
return this.emitter.on("router:afterEach", hook);
|
|
@@ -1636,14 +1964,20 @@ class Router {
|
|
|
1636
1964
|
* Registers a global error handler for navigation errors.
|
|
1637
1965
|
* @param {(error: Error, to?: RouteLocation, from?: RouteLocation) => void} handler - The error handler function.
|
|
1638
1966
|
* @returns {() => void} A function to unregister the handler.
|
|
1967
|
+
* @listens router:error
|
|
1639
1968
|
*/
|
|
1640
1969
|
onError(handler) {
|
|
1641
|
-
return this.emitter.on("router:
|
|
1970
|
+
return this.emitter.on("router:error", handler);
|
|
1642
1971
|
}
|
|
1643
1972
|
|
|
1644
1973
|
/**
|
|
1645
1974
|
* Registers a plugin with the router.
|
|
1646
|
-
*
|
|
1975
|
+
* Logs a warning if the plugin is already registered.
|
|
1976
|
+
*
|
|
1977
|
+
* @param {RouterPlugin} plugin - The plugin to register (must have install method).
|
|
1978
|
+
* @param {Record<string, unknown>} [options={}] - Options to pass to plugin.install().
|
|
1979
|
+
* @returns {void}
|
|
1980
|
+
* @throws {Error} If plugin does not have an install method.
|
|
1647
1981
|
*/
|
|
1648
1982
|
use(plugin, options = {}) {
|
|
1649
1983
|
if (typeof plugin.install !== "function") {
|
|
@@ -1706,7 +2040,9 @@ class Router {
|
|
|
1706
2040
|
|
|
1707
2041
|
/**
|
|
1708
2042
|
* Sets a custom error handler. Used by error handling plugins.
|
|
1709
|
-
*
|
|
2043
|
+
* Logs a warning if the provided handler is invalid (missing required methods).
|
|
2044
|
+
* @param {RouterErrorHandler} errorHandler - The error handler object with handle, warn, and log methods.
|
|
2045
|
+
* @returns {void}
|
|
1710
2046
|
*/
|
|
1711
2047
|
setErrorHandler(errorHandler) {
|
|
1712
2048
|
if (
|
|
@@ -1724,18 +2060,6 @@ class Router {
|
|
|
1724
2060
|
}
|
|
1725
2061
|
}
|
|
1726
2062
|
|
|
1727
|
-
/**
|
|
1728
|
-
* @typedef {Object} RouterOptions
|
|
1729
|
-
* @property {string} mount - A CSS selector for the main element where the app is mounted.
|
|
1730
|
-
* @property {RouteDefinition[]} routes - An array of route definitions.
|
|
1731
|
-
* @property {'hash' | 'query' | 'history'} [mode='hash'] - The routing mode.
|
|
1732
|
-
* @property {string} [queryParam='page'] - The query parameter to use in 'query' mode.
|
|
1733
|
-
* @property {string} [viewSelector='view'] - The selector for the view element within a layout.
|
|
1734
|
-
* @property {boolean} [autoStart=true] - Whether to start the router automatically.
|
|
1735
|
-
* @property {NavigationGuard} [onBeforeEach] - A global guard executed before every navigation.
|
|
1736
|
-
* @property {string | ComponentDefinition | (() => Promise<{default: ComponentDefinition}>)} [globalLayout] - A global layout for all routes. Can be overridden by a route's specific layout.
|
|
1737
|
-
*/
|
|
1738
|
-
|
|
1739
2063
|
/**
|
|
1740
2064
|
* @class 🚀 RouterPlugin
|
|
1741
2065
|
* @classdesc A powerful, reactive, and flexible Router Plugin for Eleva applications.
|
|
@@ -1779,7 +2103,7 @@ export const RouterPlugin = {
|
|
|
1779
2103
|
* Plugin version
|
|
1780
2104
|
* @type {string}
|
|
1781
2105
|
*/
|
|
1782
|
-
version: "1.0
|
|
2106
|
+
version: "1.1.0",
|
|
1783
2107
|
|
|
1784
2108
|
/**
|
|
1785
2109
|
* Plugin description
|
|
@@ -1790,16 +2114,25 @@ export const RouterPlugin = {
|
|
|
1790
2114
|
/**
|
|
1791
2115
|
* Installs the RouterPlugin into an Eleva instance.
|
|
1792
2116
|
*
|
|
1793
|
-
* @
|
|
1794
|
-
* @param {
|
|
1795
|
-
* @param {
|
|
1796
|
-
* @param {
|
|
1797
|
-
* @param {
|
|
1798
|
-
* @param {
|
|
1799
|
-
* @param {string} [options.
|
|
1800
|
-
* @param {
|
|
1801
|
-
* @param {
|
|
1802
|
-
* @param {
|
|
2117
|
+
* @public
|
|
2118
|
+
* @param {Eleva} eleva - The Eleva instance.
|
|
2119
|
+
* @param {RouterOptions} options - Router configuration options.
|
|
2120
|
+
* @param {string} options.mount - A CSS selector for the main element where the app is mounted.
|
|
2121
|
+
* @param {RouteDefinition[]} options.routes - An array of route definitions.
|
|
2122
|
+
* @param {'hash' | 'query' | 'history'} [options.mode='hash'] - The routing mode.
|
|
2123
|
+
* @param {string} [options.queryParam='view'] - The query parameter to use in 'query' mode.
|
|
2124
|
+
* @param {string} [options.viewSelector='view'] - Base selector for the view element (matched as #id, .class, [data-*], or raw selector).
|
|
2125
|
+
* @param {boolean} [options.autoStart=true] - Whether to start the router automatically.
|
|
2126
|
+
* @param {NavigationGuard} [options.onBeforeEach] - A global guard executed before every navigation.
|
|
2127
|
+
* @param {RouteComponent} [options.globalLayout] - A global layout for all routes.
|
|
2128
|
+
* @returns {Router} The created router instance.
|
|
2129
|
+
* @throws {Error} If 'mount' option is not provided.
|
|
2130
|
+
* @throws {Error} If 'routes' option is not an array.
|
|
2131
|
+
* @throws {Error} If component registration fails during route processing.
|
|
2132
|
+
* @description
|
|
2133
|
+
* Registers route/layout components, sets `eleva.router`, and adds helpers
|
|
2134
|
+
* (`eleva.navigate`, `eleva.getCurrentRoute`, `eleva.getRouteParams`, `eleva.getRouteQuery`).
|
|
2135
|
+
* When `autoStart` is enabled, startup is scheduled via microtask.
|
|
1803
2136
|
*
|
|
1804
2137
|
* @example
|
|
1805
2138
|
* // main.js
|
|
@@ -1832,9 +2165,10 @@ export const RouterPlugin = {
|
|
|
1832
2165
|
* Registers a component definition with the Eleva instance.
|
|
1833
2166
|
* This method handles both inline component objects and pre-registered component names.
|
|
1834
2167
|
*
|
|
1835
|
-
* @
|
|
1836
|
-
* @param {
|
|
1837
|
-
* @
|
|
2168
|
+
* @inner
|
|
2169
|
+
* @param {unknown} def - The component definition to register.
|
|
2170
|
+
* @param {string} type - The type of component for naming (e.g., "Route", "Layout").
|
|
2171
|
+
* @returns {string | null} The registered component name or null if no definition provided.
|
|
1838
2172
|
*/
|
|
1839
2173
|
const register = (def, type) => {
|
|
1840
2174
|
if (!def) return null;
|
|
@@ -1868,6 +2202,7 @@ export const RouterPlugin = {
|
|
|
1868
2202
|
});
|
|
1869
2203
|
|
|
1870
2204
|
const router = new Router(eleva, options);
|
|
2205
|
+
/** @type {Router} */
|
|
1871
2206
|
eleva.router = router;
|
|
1872
2207
|
|
|
1873
2208
|
if (options.autoStart !== false) {
|
|
@@ -1886,18 +2221,28 @@ export const RouterPlugin = {
|
|
|
1886
2221
|
});
|
|
1887
2222
|
|
|
1888
2223
|
// Add utility methods for manual router access
|
|
2224
|
+
/** @type {NavigateFunction} */
|
|
1889
2225
|
eleva.navigate = router.navigate.bind(router);
|
|
2226
|
+
/** @type {() => RouteLocation | null} */
|
|
1890
2227
|
eleva.getCurrentRoute = () => router.currentRoute.value;
|
|
2228
|
+
/** @type {() => RouteParams} */
|
|
1891
2229
|
eleva.getRouteParams = () => router.currentParams.value;
|
|
2230
|
+
/** @type {() => QueryParams} */
|
|
1892
2231
|
eleva.getRouteQuery = () => router.currentQuery.value;
|
|
1893
2232
|
|
|
1894
2233
|
return router;
|
|
1895
2234
|
},
|
|
1896
2235
|
|
|
1897
2236
|
/**
|
|
1898
|
-
* Uninstalls the plugin from the Eleva instance
|
|
2237
|
+
* Uninstalls the plugin from the Eleva instance.
|
|
1899
2238
|
*
|
|
1900
|
-
* @
|
|
2239
|
+
* @public
|
|
2240
|
+
* @async
|
|
2241
|
+
* @param {Eleva} eleva - The Eleva instance.
|
|
2242
|
+
* @returns {Promise<void>}
|
|
2243
|
+
* @description
|
|
2244
|
+
* Destroys the router instance, removes `eleva.router`, and deletes helper methods
|
|
2245
|
+
* (`eleva.navigate`, `eleva.getCurrentRoute`, `eleva.getRouteParams`, `eleva.getRouteQuery`).
|
|
1901
2246
|
*/
|
|
1902
2247
|
async uninstall(eleva) {
|
|
1903
2248
|
if (eleva.router) {
|