eleva 1.0.0-rc.1 → 1.0.0-rc.10

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