eleva 1.0.0-rc.1 → 1.0.0-rc.11

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 (65) hide show
  1. package/README.md +505 -41
  2. package/dist/eleva-plugins.cjs.js +3397 -0
  3. package/dist/eleva-plugins.cjs.js.map +1 -0
  4. package/dist/eleva-plugins.esm.js +3392 -0
  5. package/dist/eleva-plugins.esm.js.map +1 -0
  6. package/dist/eleva-plugins.umd.js +3403 -0
  7. package/dist/eleva-plugins.umd.js.map +1 -0
  8. package/dist/eleva-plugins.umd.min.js +3 -0
  9. package/dist/eleva-plugins.umd.min.js.map +1 -0
  10. package/dist/eleva.cjs.js +617 -118
  11. package/dist/eleva.cjs.js.map +1 -1
  12. package/dist/eleva.d.ts +612 -75
  13. package/dist/eleva.esm.js +617 -118
  14. package/dist/eleva.esm.js.map +1 -1
  15. package/dist/eleva.umd.js +617 -118
  16. package/dist/eleva.umd.js.map +1 -1
  17. package/dist/eleva.umd.min.js +2 -2
  18. package/dist/eleva.umd.min.js.map +1 -1
  19. package/dist/plugins/attr.umd.js +232 -0
  20. package/dist/plugins/attr.umd.js.map +1 -0
  21. package/dist/plugins/attr.umd.min.js +3 -0
  22. package/dist/plugins/attr.umd.min.js.map +1 -0
  23. package/dist/plugins/props.umd.js +712 -0
  24. package/dist/plugins/props.umd.js.map +1 -0
  25. package/dist/plugins/props.umd.min.js +3 -0
  26. package/dist/plugins/props.umd.min.js.map +1 -0
  27. package/dist/plugins/router.umd.js +1808 -0
  28. package/dist/plugins/router.umd.js.map +1 -0
  29. package/dist/plugins/router.umd.min.js +3 -0
  30. package/dist/plugins/router.umd.min.js.map +1 -0
  31. package/dist/plugins/store.umd.js +685 -0
  32. package/dist/plugins/store.umd.js.map +1 -0
  33. package/dist/plugins/store.umd.min.js +3 -0
  34. package/dist/plugins/store.umd.min.js.map +1 -0
  35. package/package.json +107 -45
  36. package/src/core/Eleva.js +247 -63
  37. package/src/modules/Emitter.js +98 -8
  38. package/src/modules/Renderer.js +66 -36
  39. package/src/modules/Signal.js +85 -8
  40. package/src/modules/TemplateEngine.js +121 -13
  41. package/src/plugins/Attr.js +255 -0
  42. package/src/plugins/Props.js +593 -0
  43. package/src/plugins/Router.js +1922 -0
  44. package/src/plugins/Store.js +744 -0
  45. package/src/plugins/index.js +40 -0
  46. package/types/core/Eleva.d.ts +217 -50
  47. package/types/core/Eleva.d.ts.map +1 -1
  48. package/types/modules/Emitter.d.ts +111 -12
  49. package/types/modules/Emitter.d.ts.map +1 -1
  50. package/types/modules/Renderer.d.ts +68 -3
  51. package/types/modules/Renderer.d.ts.map +1 -1
  52. package/types/modules/Signal.d.ts +92 -10
  53. package/types/modules/Signal.d.ts.map +1 -1
  54. package/types/modules/TemplateEngine.d.ts +131 -15
  55. package/types/modules/TemplateEngine.d.ts.map +1 -1
  56. package/types/plugins/Attr.d.ts +29 -0
  57. package/types/plugins/Attr.d.ts.map +1 -0
  58. package/types/plugins/Props.d.ts +49 -0
  59. package/types/plugins/Props.d.ts.map +1 -0
  60. package/types/plugins/Router.d.ts +1000 -0
  61. package/types/plugins/Router.d.ts.map +1 -0
  62. package/types/plugins/Store.d.ts +87 -0
  63. package/types/plugins/Store.d.ts.map +1 -0
  64. package/types/plugins/index.d.ts +5 -0
  65. package/types/plugins/index.d.ts.map +1 -0
@@ -0,0 +1,1000 @@
1
+ export type RouterPlugin = {
2
+ /**
3
+ * - Unique plugin identifier.
4
+ */
5
+ name: string;
6
+ /**
7
+ * - Plugin version (recommended to match router version).
8
+ */
9
+ version?: string | undefined;
10
+ /**
11
+ * - Installation function.
12
+ */
13
+ install: (router: Router, options?: Record<string, any>) => void;
14
+ /**
15
+ * - Cleanup function called on router.destroy().
16
+ */
17
+ destroy?: ((router: Router) => void | Promise<void>) | undefined;
18
+ };
19
+ export namespace RouterPlugin {
20
+ let name: string;
21
+ let version: string;
22
+ let description: string;
23
+ /**
24
+ * Installs the RouterPlugin into an Eleva instance.
25
+ *
26
+ * @param {Eleva} eleva - The Eleva instance
27
+ * @param {RouterOptions} options - Router configuration options
28
+ * @param {string} options.mount - A CSS selector for the main element where the app is mounted
29
+ * @param {RouteDefinition[]} options.routes - An array of route definitions
30
+ * @param {'hash' | 'query' | 'history'} [options.mode='hash'] - The routing mode
31
+ * @param {string} [options.queryParam='page'] - The query parameter to use in 'query' mode
32
+ * @param {string} [options.viewSelector='view'] - The selector for the view element within a layout
33
+ * @param {boolean} [options.autoStart=true] - Whether to start the router automatically
34
+ * @param {NavigationGuard} [options.onBeforeEach] - A global guard executed before every navigation
35
+ * @param {string | ComponentDefinition | (() => Promise<{default: ComponentDefinition}>)} [options.globalLayout] - A global layout for all routes
36
+ *
37
+ * @example
38
+ * // main.js
39
+ * import Eleva from 'eleva';
40
+ * import { RouterPlugin } from './plugins/RouterPlugin.js';
41
+ *
42
+ * const app = new Eleva('myApp');
43
+ *
44
+ * const HomePage = { template: () => `<h1>Home</h1>` };
45
+ * const AboutPage = { template: () => `<h1>About Us</h1>` };
46
+ *
47
+ * app.use(RouterPlugin, {
48
+ * mount: '#app',
49
+ * routes: [
50
+ * { path: '/', component: HomePage },
51
+ * { path: '/about', component: AboutPage }
52
+ * ]
53
+ * });
54
+ */
55
+ function install(eleva: Eleva, options?: RouterOptions): Router;
56
+ /**
57
+ * Uninstalls the plugin from the Eleva instance
58
+ *
59
+ * @param {Eleva} eleva - The Eleva instance
60
+ */
61
+ function uninstall(eleva: Eleva): Promise<void>;
62
+ }
63
+ export { RouterPlugin as Router };
64
+ export type Eleva = any;
65
+ export type Signal = any;
66
+ export type ComponentDefinition = any;
67
+ export type Emitter = any;
68
+ export type MountResult = any;
69
+ /**
70
+ * The routing mode determines how the router manages URL state.
71
+ * - `hash`: Uses URL hash (e.g., `/#/path`) - works without server config
72
+ * - `history`: Uses HTML5 History API (e.g., `/path`) - requires server config
73
+ * - `query`: Uses query parameters (e.g., `?view=/path`) - useful for embedded apps
74
+ */
75
+ export type RouterMode = "hash" | "history" | "query";
76
+ export type RouterOptions = {
77
+ /**
78
+ * - The routing mode to use.
79
+ */
80
+ mode?: RouterMode | undefined;
81
+ /**
82
+ * - Query parameter name for 'query' mode.
83
+ */
84
+ queryParam?: string | undefined;
85
+ /**
86
+ * - Selector for the view container element.
87
+ */
88
+ viewSelector?: string | undefined;
89
+ /**
90
+ * - CSS selector for the mount point element.
91
+ */
92
+ mount: string;
93
+ /**
94
+ * - Array of route definitions.
95
+ */
96
+ routes: RouteDefinition[];
97
+ /**
98
+ * - Default layout for all routes.
99
+ */
100
+ globalLayout?: string | ComponentDefinition;
101
+ /**
102
+ * - Global navigation guard.
103
+ */
104
+ onBeforeEach?: NavigationGuard | undefined;
105
+ };
106
+ export type NavigationTarget = {
107
+ /**
108
+ * - The target path (can include params like '/users/:id').
109
+ */
110
+ path: string;
111
+ /**
112
+ * - Route parameters to inject into the path.
113
+ */
114
+ params?: Record<string, string> | undefined;
115
+ /**
116
+ * - Query parameters to append.
117
+ */
118
+ query?: Record<string, string> | undefined;
119
+ /**
120
+ * - Whether to replace current history entry.
121
+ */
122
+ replace?: boolean | undefined;
123
+ /**
124
+ * - State object to pass to history.
125
+ */
126
+ state?: Record<string, any> | undefined;
127
+ };
128
+ export type ScrollPosition = {
129
+ /**
130
+ * - Horizontal scroll position.
131
+ */
132
+ x: number;
133
+ /**
134
+ * - Vertical scroll position.
135
+ */
136
+ y: number;
137
+ };
138
+ export type RouteSegment = {
139
+ /**
140
+ * - The segment type.
141
+ */
142
+ type: "static" | "param";
143
+ /**
144
+ * - The segment value (for static) or empty string (for param).
145
+ */
146
+ value: string;
147
+ /**
148
+ * - The parameter name (for param segments).
149
+ */
150
+ name?: string | undefined;
151
+ };
152
+ export type RouteMatch = {
153
+ /**
154
+ * - The matched route definition.
155
+ */
156
+ route: RouteDefinition;
157
+ /**
158
+ * - The extracted route parameters.
159
+ */
160
+ params: Record<string, string>;
161
+ };
162
+ export type RouteMeta = Record<string, any>;
163
+ export type RouterErrorHandler = {
164
+ /**
165
+ * - Throws a formatted error.
166
+ */
167
+ handle: (error: Error, context: string, details?: Record<string, any>) => void;
168
+ /**
169
+ * - Logs a warning.
170
+ */
171
+ warn: (message: string, details?: Record<string, any>) => void;
172
+ /**
173
+ * - Logs an error without throwing.
174
+ */
175
+ log: (message: string, error: Error, details?: Record<string, any>) => void;
176
+ };
177
+ export type NavigationContextCallback = (context: NavigationContext) => void | Promise<void>;
178
+ export type ResolveContextCallback = (context: ResolveContext) => void | Promise<void>;
179
+ export type RenderContextCallback = (context: RenderContext) => void | Promise<void>;
180
+ export type ScrollContextCallback = (context: ScrollContext) => void | Promise<void>;
181
+ export type RouteChangeCallback = (to: RouteLocation, from: RouteLocation | null) => void | Promise<void>;
182
+ export type RouterErrorCallback = (error: Error, to?: RouteLocation | undefined, from?: RouteLocation | null | undefined) => void | Promise<void>;
183
+ export type RouterReadyCallback = (router: Router) => void | Promise<void>;
184
+ export type RouteAddedCallback = (route: RouteDefinition) => void | Promise<void>;
185
+ export type RouteRemovedCallback = (route: RouteDefinition) => void | Promise<void>;
186
+ export type RouteLocation = {
187
+ /**
188
+ * - The path of the route (e.g., '/users/123').
189
+ */
190
+ path: string;
191
+ /**
192
+ * - Query parameters as key-value pairs.
193
+ */
194
+ query: Record<string, string>;
195
+ /**
196
+ * - The complete URL including hash, path, and query string.
197
+ */
198
+ fullUrl: string;
199
+ /**
200
+ * - Dynamic route parameters (e.g., `{ id: '123' }`).
201
+ */
202
+ params: Record<string, string>;
203
+ /**
204
+ * - Metadata associated with the matched route.
205
+ */
206
+ meta: RouteMeta;
207
+ /**
208
+ * - The optional name of the matched route.
209
+ */
210
+ name?: string | undefined;
211
+ /**
212
+ * - The raw route definition object that was matched.
213
+ */
214
+ matched: RouteDefinition;
215
+ };
216
+ /**
217
+ * The return value of a navigation guard.
218
+ * - `true` or `undefined/void`: Allow navigation
219
+ * - `false`: Abort navigation
220
+ * - `string`: Redirect to path
221
+ * - `NavigationTarget`: Redirect with options
222
+ */
223
+ export type NavigationGuardResult = boolean | string | NavigationTarget | void;
224
+ export type NavigationGuard = (to: RouteLocation, from: RouteLocation | null) => NavigationGuardResult | Promise<NavigationGuardResult>;
225
+ export type NavigationHook = (to: RouteLocation, from: RouteLocation | null) => void | Promise<void>;
226
+ export type NavigationContext = {
227
+ /**
228
+ * - The target route location.
229
+ */
230
+ to: RouteLocation;
231
+ /**
232
+ * - The source route location.
233
+ */
234
+ from: RouteLocation | null;
235
+ /**
236
+ * - Whether navigation has been cancelled.
237
+ */
238
+ cancelled: boolean;
239
+ /**
240
+ * - Redirect target if navigation should redirect.
241
+ */
242
+ redirectTo: string | {
243
+ path: string;
244
+ } | null;
245
+ };
246
+ export type ResolveContext = {
247
+ /**
248
+ * - The target route location.
249
+ */
250
+ to: RouteLocation;
251
+ /**
252
+ * - The source route location.
253
+ */
254
+ from: RouteLocation | null;
255
+ /**
256
+ * - The matched route definition.
257
+ */
258
+ route: RouteDefinition;
259
+ /**
260
+ * - The resolved layout component (available in afterResolve).
261
+ */
262
+ layoutComponent: ComponentDefinition | null;
263
+ /**
264
+ * - The resolved page component (available in afterResolve).
265
+ */
266
+ pageComponent: ComponentDefinition | null;
267
+ /**
268
+ * - Whether navigation has been cancelled.
269
+ */
270
+ cancelled: boolean;
271
+ /**
272
+ * - Redirect target if navigation should redirect.
273
+ */
274
+ redirectTo: string | {
275
+ path: string;
276
+ } | null;
277
+ };
278
+ export type RenderContext = {
279
+ /**
280
+ * - The target route location.
281
+ */
282
+ to: RouteLocation;
283
+ /**
284
+ * - The source route location.
285
+ */
286
+ from: RouteLocation | null;
287
+ /**
288
+ * - The layout component being rendered.
289
+ */
290
+ layoutComponent: ComponentDefinition | null;
291
+ /**
292
+ * - The page component being rendered.
293
+ */
294
+ pageComponent: ComponentDefinition;
295
+ };
296
+ export type ScrollContext = {
297
+ /**
298
+ * - The target route location.
299
+ */
300
+ to: RouteLocation;
301
+ /**
302
+ * - The source route location.
303
+ */
304
+ from: RouteLocation | null;
305
+ /**
306
+ * - The saved scroll position (if navigating via back/forward).
307
+ */
308
+ savedPosition: {
309
+ x: number;
310
+ y: number;
311
+ } | null;
312
+ };
313
+ /**
314
+ * A component that can be rendered for a route.
315
+ * - `string`: Name of a registered component
316
+ * - `ComponentDefinition`: Inline component definition
317
+ * - `() => Promise<{default: ComponentDefinition}>`: Lazy-loaded component (e.g., `() => import('./Page.js')`)
318
+ */
319
+ export type RouteComponent = string | ComponentDefinition | (() => Promise<{
320
+ default: ComponentDefinition;
321
+ }>);
322
+ export type RouteDefinition = {
323
+ /**
324
+ * - URL path pattern. Supports:
325
+ * - Static: `'/about'`
326
+ * - Dynamic params: `'/users/:id'`
327
+ * - Wildcard: `'*'` (catch-all, must be last)
328
+ */
329
+ path: string;
330
+ /**
331
+ * - The component to render for this route.
332
+ */
333
+ component: RouteComponent;
334
+ /**
335
+ * - Optional layout component to wrap the route component.
336
+ */
337
+ layout?: RouteComponent;
338
+ /**
339
+ * - Optional route name for programmatic navigation.
340
+ */
341
+ name?: string | undefined;
342
+ /**
343
+ * - Optional metadata (auth flags, titles, etc.).
344
+ */
345
+ meta?: RouteMeta | undefined;
346
+ /**
347
+ * - Route-specific guard before entering.
348
+ */
349
+ beforeEnter?: NavigationGuard | undefined;
350
+ /**
351
+ * - Hook after entering and component is mounted.
352
+ */
353
+ afterEnter?: NavigationHook | undefined;
354
+ /**
355
+ * - Guard before leaving this route.
356
+ */
357
+ beforeLeave?: NavigationGuard | undefined;
358
+ /**
359
+ * - Hook after leaving and component is unmounted.
360
+ */
361
+ afterLeave?: NavigationHook | undefined;
362
+ /**
363
+ * - Internal: parsed path segments (added by router).
364
+ */
365
+ segments?: RouteSegment[] | undefined;
366
+ };
367
+ /**
368
+ * @typedef {Object} RouteLocation
369
+ * @property {string} path - The path of the route (e.g., '/users/123').
370
+ * @property {Record<string, string>} query - Query parameters as key-value pairs.
371
+ * @property {string} fullUrl - The complete URL including hash, path, and query string.
372
+ * @property {Record<string, string>} params - Dynamic route parameters (e.g., `{ id: '123' }`).
373
+ * @property {RouteMeta} meta - Metadata associated with the matched route.
374
+ * @property {string} [name] - The optional name of the matched route.
375
+ * @property {RouteDefinition} matched - The raw route definition object that was matched.
376
+ * @description Represents the current or target location in the router.
377
+ */
378
+ /**
379
+ * @typedef {boolean | string | NavigationTarget | void} NavigationGuardResult
380
+ * The return value of a navigation guard.
381
+ * - `true` or `undefined/void`: Allow navigation
382
+ * - `false`: Abort navigation
383
+ * - `string`: Redirect to path
384
+ * - `NavigationTarget`: Redirect with options
385
+ */
386
+ /**
387
+ * @callback NavigationGuard
388
+ * @param {RouteLocation} to - The target route location.
389
+ * @param {RouteLocation | null} from - The source route location (null on initial navigation).
390
+ * @returns {NavigationGuardResult | Promise<NavigationGuardResult>}
391
+ * @description A function that controls navigation flow. Runs before navigation is confirmed.
392
+ * @example
393
+ * // Simple auth guard
394
+ * const authGuard = (to, from) => {
395
+ * if (to.meta.requiresAuth && !isLoggedIn()) {
396
+ * return '/login'; // Redirect
397
+ * }
398
+ * // Allow navigation (implicit return undefined)
399
+ * };
400
+ */
401
+ /**
402
+ * @callback NavigationHook
403
+ * @param {RouteLocation} to - The target route location.
404
+ * @param {RouteLocation | null} from - The source route location.
405
+ * @returns {void | Promise<void>}
406
+ * @description A lifecycle hook for side effects. Does not affect navigation flow.
407
+ * @example
408
+ * // Analytics hook
409
+ * const analyticsHook = (to, from) => {
410
+ * analytics.trackPageView(to.path);
411
+ * };
412
+ */
413
+ /**
414
+ * @typedef {Object} RouterPlugin
415
+ * @property {string} name - Unique plugin identifier.
416
+ * @property {string} [version] - Plugin version (recommended to match router version).
417
+ * @property {(router: Router, options?: Record<string, any>) => void} install - Installation function.
418
+ * @property {(router: Router) => void | Promise<void>} [destroy] - Cleanup function called on router.destroy().
419
+ * @description Interface for router plugins. Plugins can extend router functionality.
420
+ * @example
421
+ * const AnalyticsPlugin = {
422
+ * name: 'analytics',
423
+ * version: '1.0.0',
424
+ * install(router, options) {
425
+ * router.emitter.on('router:afterEach', (to, from) => {
426
+ * analytics.track(to.path);
427
+ * });
428
+ * }
429
+ * };
430
+ */
431
+ /**
432
+ * @typedef {Object} NavigationContext
433
+ * @property {RouteLocation} to - The target route location.
434
+ * @property {RouteLocation | null} from - The source route location.
435
+ * @property {boolean} cancelled - Whether navigation has been cancelled.
436
+ * @property {string | {path: string} | null} redirectTo - Redirect target if navigation should redirect.
437
+ * @description A context object passed to navigation events that plugins can modify to control navigation flow.
438
+ */
439
+ /**
440
+ * @typedef {Object} ResolveContext
441
+ * @property {RouteLocation} to - The target route location.
442
+ * @property {RouteLocation | null} from - The source route location.
443
+ * @property {RouteDefinition} route - The matched route definition.
444
+ * @property {ComponentDefinition | null} layoutComponent - The resolved layout component (available in afterResolve).
445
+ * @property {ComponentDefinition | null} pageComponent - The resolved page component (available in afterResolve).
446
+ * @property {boolean} cancelled - Whether navigation has been cancelled.
447
+ * @property {string | {path: string} | null} redirectTo - Redirect target if navigation should redirect.
448
+ * @description A context object passed to component resolution events.
449
+ */
450
+ /**
451
+ * @typedef {Object} RenderContext
452
+ * @property {RouteLocation} to - The target route location.
453
+ * @property {RouteLocation | null} from - The source route location.
454
+ * @property {ComponentDefinition | null} layoutComponent - The layout component being rendered.
455
+ * @property {ComponentDefinition} pageComponent - The page component being rendered.
456
+ * @description A context object passed to render events.
457
+ */
458
+ /**
459
+ * @typedef {Object} ScrollContext
460
+ * @property {RouteLocation} to - The target route location.
461
+ * @property {RouteLocation | null} from - The source route location.
462
+ * @property {{x: number, y: number} | null} savedPosition - The saved scroll position (if navigating via back/forward).
463
+ * @description A context object passed to scroll events for plugins to handle scroll behavior.
464
+ */
465
+ /**
466
+ * @typedef {string | ComponentDefinition | (() => Promise<{default: ComponentDefinition}>)} RouteComponent
467
+ * A component that can be rendered for a route.
468
+ * - `string`: Name of a registered component
469
+ * - `ComponentDefinition`: Inline component definition
470
+ * - `() => Promise<{default: ComponentDefinition}>`: Lazy-loaded component (e.g., `() => import('./Page.js')`)
471
+ */
472
+ /**
473
+ * @typedef {Object} RouteDefinition
474
+ * @property {string} path - URL path pattern. Supports:
475
+ * - Static: `'/about'`
476
+ * - Dynamic params: `'/users/:id'`
477
+ * - Wildcard: `'*'` (catch-all, must be last)
478
+ * @property {RouteComponent} component - The component to render for this route.
479
+ * @property {RouteComponent} [layout] - Optional layout component to wrap the route component.
480
+ * @property {string} [name] - Optional route name for programmatic navigation.
481
+ * @property {RouteMeta} [meta] - Optional metadata (auth flags, titles, etc.).
482
+ * @property {NavigationGuard} [beforeEnter] - Route-specific guard before entering.
483
+ * @property {NavigationHook} [afterEnter] - Hook after entering and component is mounted.
484
+ * @property {NavigationGuard} [beforeLeave] - Guard before leaving this route.
485
+ * @property {NavigationHook} [afterLeave] - Hook after leaving and component is unmounted.
486
+ * @property {RouteSegment[]} [segments] - Internal: parsed path segments (added by router).
487
+ * @description Defines a route in the application.
488
+ * @example
489
+ * // Static route
490
+ * { path: '/about', component: AboutPage }
491
+ *
492
+ * // Dynamic route with params
493
+ * { path: '/users/:id', component: UserPage, meta: { requiresAuth: true } }
494
+ *
495
+ * // Lazy-loaded route with layout
496
+ * {
497
+ * path: '/dashboard',
498
+ * component: () => import('./Dashboard.js'),
499
+ * layout: DashboardLayout,
500
+ * beforeEnter: (to, from) => isLoggedIn() || '/login'
501
+ * }
502
+ *
503
+ * // Catch-all 404 route (must be last)
504
+ * { path: '*', component: NotFoundPage }
505
+ */
506
+ /**
507
+ * @class Router
508
+ * @classdesc A powerful, reactive, and flexible Router Plugin for Eleva.
509
+ * This class manages all routing logic, including state, navigation, and rendering.
510
+ *
511
+ * ## Features
512
+ * - Multiple routing modes (hash, history, query)
513
+ * - Reactive route state via Signals
514
+ * - Navigation guards and lifecycle hooks
515
+ * - Lazy-loaded components
516
+ * - Layout system
517
+ * - Plugin architecture
518
+ * - Scroll position management
519
+ *
520
+ * ## Events Reference
521
+ * | Event | Callback Type | Can Block | Description |
522
+ * |-------|--------------|-----------|-------------|
523
+ * | `router:ready` | {@link RouterReadyCallback} | No | Router initialized |
524
+ * | `router:beforeEach` | {@link NavigationContextCallback} | Yes | Before guards run |
525
+ * | `router:beforeResolve` | {@link ResolveContextCallback} | Yes | Before component loading |
526
+ * | `router:afterResolve` | {@link ResolveContextCallback} | No | After components loaded |
527
+ * | `router:afterLeave` | {@link RouteChangeCallback} | No | After leaving route |
528
+ * | `router:beforeRender` | {@link RenderContextCallback} | No | Before DOM update |
529
+ * | `router:afterRender` | {@link RenderContextCallback} | No | After DOM update |
530
+ * | `router:scroll` | {@link ScrollContextCallback} | No | For scroll behavior |
531
+ * | `router:afterEnter` | {@link RouteChangeCallback} | No | After entering route |
532
+ * | `router:afterEach` | {@link RouteChangeCallback} | No | Navigation complete |
533
+ * | `router:onError` | {@link RouterErrorCallback} | No | Navigation error |
534
+ * | `router:routeAdded` | {@link RouteAddedCallback} | No | Dynamic route added |
535
+ * | `router:routeRemoved` | {@link RouteRemovedCallback} | No | Dynamic route removed |
536
+ *
537
+ * ## Reactive Signals
538
+ * - `currentRoute: Signal<RouteLocation | null>` - Current route info
539
+ * - `previousRoute: Signal<RouteLocation | null>` - Previous route info
540
+ * - `currentParams: Signal<Record<string, string>>` - Current route params
541
+ * - `currentQuery: Signal<Record<string, string>>` - Current query params
542
+ * - `currentLayout: Signal<MountResult | null>` - Mounted layout instance
543
+ * - `currentView: Signal<MountResult | null>` - Mounted view instance
544
+ * - `isReady: Signal<boolean>` - Router readiness state
545
+ *
546
+ * @note Internal API Access Policy:
547
+ * As a core Eleva plugin, the Router may access internal Eleva APIs (prefixed with _)
548
+ * such as `eleva._components`. This is intentional and these internal APIs are
549
+ * considered stable for official plugins. Third-party plugins should avoid
550
+ * accessing internal APIs as they may change without notice.
551
+ *
552
+ * @example
553
+ * // Basic setup
554
+ * const router = new Router(eleva, {
555
+ * mode: 'hash',
556
+ * mount: '#app',
557
+ * routes: [
558
+ * { path: '/', component: HomePage },
559
+ * { path: '/users/:id', component: UserPage },
560
+ * { path: '*', component: NotFoundPage }
561
+ * ]
562
+ * });
563
+ *
564
+ * // Start router
565
+ * await router.start();
566
+ *
567
+ * // Navigate programmatically
568
+ * const success = await router.navigate('/users/123');
569
+ *
570
+ * // Watch for route changes
571
+ * router.currentRoute.watch((route) => {
572
+ * document.title = route?.meta?.title || 'My App';
573
+ * });
574
+ *
575
+ * @private
576
+ */
577
+ declare class Router {
578
+ /**
579
+ * Creates an instance of the Router.
580
+ * @param {Eleva} eleva - The Eleva framework instance.
581
+ * @param {RouterOptions} options - The configuration options for the router.
582
+ */
583
+ constructor(eleva: Eleva, options?: RouterOptions);
584
+ /** @type {Eleva} The Eleva framework instance. */
585
+ eleva: Eleva;
586
+ /** @type {RouterOptions} The merged router options. */
587
+ options: RouterOptions;
588
+ /** @private @type {RouteDefinition[]} The processed list of route definitions. */
589
+ private routes;
590
+ /** @private @type {import('eleva').Emitter} The shared Eleva event emitter for global hooks. */
591
+ private emitter;
592
+ /** @private @type {boolean} A flag indicating if the router has been started. */
593
+ private isStarted;
594
+ /** @private @type {boolean} A flag to prevent navigation loops from history events. */
595
+ private _isNavigating;
596
+ /** @private @type {number} Counter for tracking navigation operations to prevent race conditions. */
597
+ private _navigationId;
598
+ /** @private @type {Array<() => void>} A collection of cleanup functions for event listeners. */
599
+ private eventListeners;
600
+ /** @type {Signal<RouteLocation | null>} A reactive signal holding the current route's information. */
601
+ currentRoute: Signal<RouteLocation | null>;
602
+ /** @type {Signal<RouteLocation | null>} A reactive signal holding the previous route's information. */
603
+ previousRoute: Signal<RouteLocation | null>;
604
+ /** @type {Signal<Object<string, string>>} A reactive signal holding the current route's parameters. */
605
+ currentParams: Signal<{
606
+ [x: string]: string;
607
+ }>;
608
+ /** @type {Signal<Object<string, string>>} A reactive signal holding the current route's query parameters. */
609
+ currentQuery: Signal<{
610
+ [x: string]: string;
611
+ }>;
612
+ /** @type {Signal<import('eleva').MountResult | null>} A reactive signal for the currently mounted layout instance. */
613
+ currentLayout: Signal<any | null>;
614
+ /** @type {Signal<import('eleva').MountResult | null>} A reactive signal for the currently mounted view (page) instance. */
615
+ currentView: Signal<any | null>;
616
+ /** @type {Signal<boolean>} A reactive signal indicating if the router is ready (started and initial navigation complete). */
617
+ isReady: Signal<boolean>;
618
+ /** @private @type {Map<string, RouterPlugin>} Map of registered plugins by name. */
619
+ private plugins;
620
+ /** @private @type {Array<NavigationGuard>} Array of global before-each navigation guards. */
621
+ private _beforeEachGuards;
622
+ /** @type {Object} The error handler instance. Can be overridden by plugins. */
623
+ errorHandler: Object;
624
+ /** @private @type {Map<string, {x: number, y: number}>} Saved scroll positions by route path. */
625
+ private _scrollPositions;
626
+ /**
627
+ * Validates the provided router options.
628
+ * @private
629
+ * @throws {Error} If the routing mode is invalid.
630
+ */
631
+ private _validateOptions;
632
+ /**
633
+ * Pre-processes route definitions to parse their path segments for efficient matching.
634
+ * @private
635
+ * @param {RouteDefinition[]} routes - The raw route definitions.
636
+ * @returns {RouteDefinition[]} The processed routes.
637
+ */
638
+ private _processRoutes;
639
+ /**
640
+ * Parses a route path string into an array of static and parameter segments.
641
+ * @private
642
+ * @param {string} path - The path pattern to parse.
643
+ * @returns {Array<{type: 'static' | 'param', value?: string, name?: string}>} An array of segment objects.
644
+ * @throws {Error} If the route path is not a valid string.
645
+ */
646
+ private _parsePathIntoSegments;
647
+ /**
648
+ * Finds the view element within a container using multiple selector strategies.
649
+ * @private
650
+ * @param {HTMLElement} container - The parent element to search within.
651
+ * @returns {HTMLElement} The found view element or the container itself as a fallback.
652
+ */
653
+ private _findViewElement;
654
+ /**
655
+ * Starts the router, initializes event listeners, and performs the initial navigation.
656
+ * @returns {Promise<Router>} The router instance for method chaining.
657
+ *
658
+ * @example
659
+ * // Basic usage
660
+ * await router.start();
661
+ *
662
+ * // Method chaining
663
+ * await router.start().then(r => r.navigate('/home'));
664
+ *
665
+ * // Reactive readiness
666
+ * router.isReady.watch((ready) => {
667
+ * if (ready) console.log('Router is ready!');
668
+ * });
669
+ */
670
+ start(): Promise<Router>;
671
+ /**
672
+ * Stops the router and cleans up all event listeners and mounted components.
673
+ * @returns {Promise<void>}
674
+ */
675
+ destroy(): Promise<void>;
676
+ /**
677
+ * Alias for destroy(). Stops the router and cleans up all resources.
678
+ * Provided for semantic consistency (start/stop pattern).
679
+ * @returns {Promise<void>}
680
+ *
681
+ * @example
682
+ * await router.start();
683
+ * // ... later
684
+ * await router.stop();
685
+ */
686
+ stop(): Promise<void>;
687
+ /**
688
+ * Programmatically navigates to a new route.
689
+ * @param {string | NavigationTarget} location - The target location as a path string or navigation target object.
690
+ * @param {Record<string, string>} [params] - Route parameters (only used when location is a string).
691
+ * @returns {Promise<boolean>} True if navigation succeeded, false if blocked by guards or failed.
692
+ *
693
+ * @example
694
+ * // Basic navigation
695
+ * await router.navigate('/users/123');
696
+ *
697
+ * // Check if navigation succeeded
698
+ * const success = await router.navigate('/protected');
699
+ * if (!success) {
700
+ * console.log('Navigation was blocked by a guard');
701
+ * }
702
+ *
703
+ * // Navigate with options
704
+ * await router.navigate({
705
+ * path: '/users/:id',
706
+ * params: { id: '123' },
707
+ * query: { tab: 'profile' },
708
+ * replace: true
709
+ * });
710
+ */
711
+ navigate(location: string | NavigationTarget, params?: Record<string, string>): Promise<boolean>;
712
+ /**
713
+ * Builds a URL for query mode.
714
+ * @private
715
+ * @param {string} path - The path to set as the query parameter.
716
+ * @returns {string} The full URL with the updated query string.
717
+ */
718
+ private _buildQueryUrl;
719
+ /**
720
+ * Checks if the target route is identical to the current route.
721
+ * @private
722
+ * @param {string} path - The target path with query string.
723
+ * @param {object} params - The target params.
724
+ * @param {object} query - The target query.
725
+ * @returns {boolean} - True if the routes are the same.
726
+ */
727
+ private _isSameRoute;
728
+ /**
729
+ * Injects dynamic parameters into a path string.
730
+ * @private
731
+ */
732
+ private _buildPath;
733
+ /**
734
+ * The handler for browser-initiated route changes (e.g., back/forward buttons).
735
+ * @private
736
+ * @param {boolean} [isPopState=true] - Whether this is a popstate event (back/forward navigation).
737
+ */
738
+ private _handleRouteChange;
739
+ /**
740
+ * Manages the core navigation lifecycle. Runs guards before committing changes.
741
+ * Emits lifecycle events that plugins can hook into:
742
+ * - router:beforeEach - Before guards run (can block/redirect via context)
743
+ * - router:beforeResolve - Before component resolution (can block/redirect)
744
+ * - router:afterResolve - After components are resolved
745
+ * - router:beforeRender - Before DOM rendering
746
+ * - router:afterRender - After DOM rendering
747
+ * - router:scroll - After render, for scroll behavior
748
+ * - router:afterEnter - After entering a route
749
+ * - router:afterLeave - After leaving a route
750
+ * - router:afterEach - After navigation completes
751
+ *
752
+ * @private
753
+ * @param {string} fullPath - The full path (e.g., '/users/123?foo=bar') to navigate to.
754
+ * @param {boolean} [isPopState=false] - Whether this navigation was triggered by popstate (back/forward).
755
+ * @returns {Promise<boolean>} - `true` if navigation succeeded, `false` if aborted.
756
+ */
757
+ private _proceedWithNavigation;
758
+ /**
759
+ * Executes all applicable navigation guards for a transition in order.
760
+ * Guards are executed in the following order:
761
+ * 1. Global beforeEach event (emitter-based, can block via context)
762
+ * 2. Global beforeEach guards (registered via onBeforeEach)
763
+ * 3. Route-specific beforeLeave guard (from the route being left)
764
+ * 4. Route-specific beforeEnter guard (from the route being entered)
765
+ *
766
+ * @private
767
+ * @param {RouteLocation} to - The target route location.
768
+ * @param {RouteLocation | null} from - The current route location (null on initial navigation).
769
+ * @param {RouteDefinition} route - The matched route definition.
770
+ * @returns {Promise<boolean>} - `false` if navigation should be aborted.
771
+ */
772
+ private _runGuards;
773
+ /**
774
+ * Resolves a string component definition to a component object.
775
+ * @private
776
+ * @param {string} def - The component name to resolve.
777
+ * @returns {ComponentDefinition} The resolved component.
778
+ * @throws {Error} If the component is not registered.
779
+ *
780
+ * @note Core plugins (Router, Attr, Props, Store) may access eleva._components
781
+ * directly. This is intentional and stable for official Eleva plugins shipped
782
+ * with the framework. Third-party plugins should use eleva.component() for
783
+ * registration and avoid direct access to internal APIs.
784
+ */
785
+ private _resolveStringComponent;
786
+ /**
787
+ * Resolves a function component definition to a component object.
788
+ * @private
789
+ * @param {Function} def - The function to resolve.
790
+ * @returns {Promise<ComponentDefinition>} The resolved component.
791
+ * @throws {Error} If the function fails to load the component.
792
+ */
793
+ private _resolveFunctionComponent;
794
+ /**
795
+ * Validates a component definition object.
796
+ * @private
797
+ * @param {any} def - The component definition to validate.
798
+ * @returns {ComponentDefinition} The validated component.
799
+ * @throws {Error} If the component definition is invalid.
800
+ */
801
+ private _validateComponentDefinition;
802
+ /**
803
+ * Resolves a component definition to a component object.
804
+ * @private
805
+ * @param {any} def - The component definition to resolve.
806
+ * @returns {Promise<ComponentDefinition | null>} The resolved component or null.
807
+ */
808
+ private _resolveComponent;
809
+ /**
810
+ * Asynchronously resolves the layout and page components for a route.
811
+ * @private
812
+ * @param {RouteDefinition} route - The route to resolve components for.
813
+ * @returns {Promise<{layoutComponent: ComponentDefinition | null, pageComponent: ComponentDefinition}>}
814
+ */
815
+ private _resolveComponents;
816
+ /**
817
+ * Renders the components for the current route into the DOM.
818
+ * @private
819
+ * @param {ComponentDefinition | null} layoutComponent - The pre-loaded layout component.
820
+ * @param {ComponentDefinition} pageComponent - The pre-loaded page component.
821
+ */
822
+ private _render;
823
+ /**
824
+ * Creates a getter function for router context properties.
825
+ * @private
826
+ * @param {string} property - The property name to access.
827
+ * @param {any} defaultValue - The default value if property is undefined.
828
+ * @returns {Function} A getter function.
829
+ */
830
+ private _createRouteGetter;
831
+ /**
832
+ * Wraps a component definition to inject router-specific context into its setup function.
833
+ * @private
834
+ * @param {ComponentDefinition} component - The component to wrap.
835
+ * @returns {ComponentDefinition} The wrapped component definition.
836
+ */
837
+ private _wrapComponent;
838
+ /**
839
+ * Recursively wraps all child components to ensure they have access to router context.
840
+ * @private
841
+ * @param {ComponentDefinition | string} component - The component to wrap (can be a definition object or a registered component name).
842
+ * @returns {ComponentDefinition | string} The wrapped component definition or the original string reference.
843
+ */
844
+ private _wrapComponentWithChildren;
845
+ /**
846
+ * Gets the current location information from the browser's window object.
847
+ * @private
848
+ * @returns {Omit<RouteLocation, 'params' | 'meta' | 'name' | 'matched'>}
849
+ */
850
+ private _getCurrentLocation;
851
+ /**
852
+ * Parses a query string into a key-value object.
853
+ * @private
854
+ */
855
+ private _parseQuery;
856
+ /**
857
+ * Matches a given path against the registered routes.
858
+ * @private
859
+ * @param {string} path - The path to match.
860
+ * @returns {{route: RouteDefinition, params: Object<string, string>} | null} The matched route and its params, or null.
861
+ */
862
+ private _matchRoute;
863
+ /**
864
+ * Adds a new route dynamically at runtime.
865
+ * The route will be processed and available for navigation immediately.
866
+ *
867
+ * @param {RouteDefinition} route - The route definition to add.
868
+ * @param {RouteDefinition} [parentRoute] - Optional parent route to add as a child (not yet implemented).
869
+ * @returns {() => void} A function to remove the added route.
870
+ *
871
+ * @example
872
+ * // Add a route dynamically
873
+ * const removeRoute = router.addRoute({
874
+ * path: '/dynamic',
875
+ * component: DynamicPage,
876
+ * meta: { title: 'Dynamic Page' }
877
+ * });
878
+ *
879
+ * // Later, remove the route
880
+ * removeRoute();
881
+ */
882
+ addRoute(route: RouteDefinition, parentRoute?: RouteDefinition): () => void;
883
+ /**
884
+ * Removes a route by its path.
885
+ *
886
+ * @param {string} path - The path of the route to remove.
887
+ * @returns {boolean} True if the route was removed, false if not found.
888
+ *
889
+ * @example
890
+ * router.removeRoute('/dynamic');
891
+ */
892
+ removeRoute(path: string): boolean;
893
+ /**
894
+ * Checks if a route with the given path exists.
895
+ *
896
+ * @param {string} path - The path to check.
897
+ * @returns {boolean} True if the route exists.
898
+ *
899
+ * @example
900
+ * if (router.hasRoute('/users/:id')) {
901
+ * console.log('User route exists');
902
+ * }
903
+ */
904
+ hasRoute(path: string): boolean;
905
+ /**
906
+ * Gets all registered routes.
907
+ *
908
+ * @returns {RouteDefinition[]} A copy of the routes array.
909
+ *
910
+ * @example
911
+ * const routes = router.getRoutes();
912
+ * console.log('Available routes:', routes.map(r => r.path));
913
+ */
914
+ getRoutes(): RouteDefinition[];
915
+ /**
916
+ * Gets a route by its path.
917
+ *
918
+ * @param {string} path - The path of the route to get.
919
+ * @returns {RouteDefinition | undefined} The route definition or undefined.
920
+ *
921
+ * @example
922
+ * const route = router.getRoute('/users/:id');
923
+ * if (route) {
924
+ * console.log('Route meta:', route.meta);
925
+ * }
926
+ */
927
+ getRoute(path: string): RouteDefinition | undefined;
928
+ /**
929
+ * Registers a global pre-navigation guard.
930
+ * Multiple guards can be registered and will be executed in order.
931
+ * Guards can also be registered via the emitter using `router:beforeEach` event.
932
+ *
933
+ * @param {NavigationGuard} guard - The guard function to register.
934
+ * @returns {() => void} A function to unregister the guard.
935
+ *
936
+ * @example
937
+ * // Register a guard
938
+ * const unregister = router.onBeforeEach((to, from) => {
939
+ * if (to.meta.requiresAuth && !isAuthenticated()) {
940
+ * return '/login';
941
+ * }
942
+ * });
943
+ *
944
+ * // Later, unregister the guard
945
+ * unregister();
946
+ */
947
+ onBeforeEach(guard: NavigationGuard): () => void;
948
+ /**
949
+ * Registers a global hook that runs after a new route component has been mounted.
950
+ * @param {NavigationHook} hook - The hook function to register.
951
+ * @returns {() => void} A function to unregister the hook.
952
+ */
953
+ onAfterEnter(hook: NavigationHook): () => void;
954
+ /**
955
+ * Registers a global hook that runs after a route component has been unmounted.
956
+ * @param {NavigationHook} hook - The hook function to register.
957
+ * @returns {() => void} A function to unregister the hook.
958
+ */
959
+ onAfterLeave(hook: NavigationHook): () => void;
960
+ /**
961
+ * Registers a global hook that runs after a navigation has been confirmed and all hooks have completed.
962
+ * @param {NavigationHook} hook - The hook function to register.
963
+ * @returns {() => void} A function to unregister the hook.
964
+ */
965
+ onAfterEach(hook: NavigationHook): () => void;
966
+ /**
967
+ * Registers a global error handler for navigation errors.
968
+ * @param {(error: Error, to?: RouteLocation, from?: RouteLocation) => void} handler - The error handler function.
969
+ * @returns {() => void} A function to unregister the handler.
970
+ */
971
+ onError(handler: (error: Error, to?: RouteLocation, from?: RouteLocation) => void): () => void;
972
+ /**
973
+ * Registers a plugin with the router.
974
+ * @param {RouterPlugin} plugin - The plugin to register.
975
+ */
976
+ use(plugin: RouterPlugin, options?: {}): void;
977
+ /**
978
+ * Gets all registered plugins.
979
+ * @returns {RouterPlugin[]} Array of registered plugins.
980
+ */
981
+ getPlugins(): RouterPlugin[];
982
+ /**
983
+ * Gets a plugin by name.
984
+ * @param {string} name - The plugin name.
985
+ * @returns {RouterPlugin | undefined} The plugin or undefined.
986
+ */
987
+ getPlugin(name: string): RouterPlugin | undefined;
988
+ /**
989
+ * Removes a plugin from the router.
990
+ * @param {string} name - The plugin name.
991
+ * @returns {boolean} True if the plugin was removed.
992
+ */
993
+ removePlugin(name: string): boolean;
994
+ /**
995
+ * Sets a custom error handler. Used by error handling plugins.
996
+ * @param {Object} errorHandler - The error handler object with handle, warn, and log methods.
997
+ */
998
+ setErrorHandler(errorHandler: Object): void;
999
+ }
1000
+ //# sourceMappingURL=Router.d.ts.map