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.
Files changed (97) hide show
  1. package/README.md +21 -10
  2. package/dist/{eleva-plugins.cjs.js → eleva-plugins.cjs} +1002 -292
  3. package/dist/eleva-plugins.cjs.map +1 -0
  4. package/dist/eleva-plugins.d.cts +1352 -0
  5. package/dist/eleva-plugins.d.cts.map +1 -0
  6. package/dist/eleva-plugins.d.ts +1352 -0
  7. package/dist/eleva-plugins.d.ts.map +1 -0
  8. package/dist/{eleva-plugins.esm.js → eleva-plugins.js} +1002 -292
  9. package/dist/eleva-plugins.js.map +1 -0
  10. package/dist/eleva-plugins.umd.js +1001 -291
  11. package/dist/eleva-plugins.umd.js.map +1 -1
  12. package/dist/eleva-plugins.umd.min.js +1 -1
  13. package/dist/eleva-plugins.umd.min.js.map +1 -1
  14. package/dist/{eleva.cjs.js → eleva.cjs} +421 -191
  15. package/dist/eleva.cjs.map +1 -0
  16. package/dist/eleva.d.cts +1329 -0
  17. package/dist/eleva.d.cts.map +1 -0
  18. package/dist/eleva.d.ts +473 -226
  19. package/dist/eleva.d.ts.map +1 -0
  20. package/dist/{eleva.esm.js → eleva.js} +422 -192
  21. package/dist/eleva.js.map +1 -0
  22. package/dist/eleva.umd.js +420 -190
  23. package/dist/eleva.umd.js.map +1 -1
  24. package/dist/eleva.umd.min.js +1 -1
  25. package/dist/eleva.umd.min.js.map +1 -1
  26. package/dist/plugins/attr.cjs +279 -0
  27. package/dist/plugins/attr.cjs.map +1 -0
  28. package/dist/plugins/attr.d.cts +101 -0
  29. package/dist/plugins/attr.d.cts.map +1 -0
  30. package/dist/plugins/attr.d.ts +101 -0
  31. package/dist/plugins/attr.d.ts.map +1 -0
  32. package/dist/plugins/attr.js +276 -0
  33. package/dist/plugins/attr.js.map +1 -0
  34. package/dist/plugins/attr.umd.js +111 -22
  35. package/dist/plugins/attr.umd.js.map +1 -1
  36. package/dist/plugins/attr.umd.min.js +1 -1
  37. package/dist/plugins/attr.umd.min.js.map +1 -1
  38. package/dist/plugins/router.cjs +1873 -0
  39. package/dist/plugins/router.cjs.map +1 -0
  40. package/dist/plugins/router.d.cts +1296 -0
  41. package/dist/plugins/router.d.cts.map +1 -0
  42. package/dist/plugins/router.d.ts +1296 -0
  43. package/dist/plugins/router.d.ts.map +1 -0
  44. package/dist/plugins/router.js +1870 -0
  45. package/dist/plugins/router.js.map +1 -0
  46. package/dist/plugins/router.umd.js +482 -186
  47. package/dist/plugins/router.umd.js.map +1 -1
  48. package/dist/plugins/router.umd.min.js +1 -1
  49. package/dist/plugins/router.umd.min.js.map +1 -1
  50. package/dist/plugins/store.cjs +920 -0
  51. package/dist/plugins/store.cjs.map +1 -0
  52. package/dist/plugins/store.d.cts +266 -0
  53. package/dist/plugins/store.d.cts.map +1 -0
  54. package/dist/plugins/store.d.ts +266 -0
  55. package/dist/plugins/store.d.ts.map +1 -0
  56. package/dist/plugins/store.js +917 -0
  57. package/dist/plugins/store.js.map +1 -0
  58. package/dist/plugins/store.umd.js +410 -85
  59. package/dist/plugins/store.umd.js.map +1 -1
  60. package/dist/plugins/store.umd.min.js +1 -1
  61. package/dist/plugins/store.umd.min.js.map +1 -1
  62. package/package.json +112 -68
  63. package/src/core/Eleva.js +195 -115
  64. package/src/index.cjs +10 -0
  65. package/src/index.js +11 -0
  66. package/src/modules/Emitter.js +68 -20
  67. package/src/modules/Renderer.js +82 -20
  68. package/src/modules/Signal.js +43 -15
  69. package/src/modules/TemplateEngine.js +50 -9
  70. package/src/plugins/Attr.js +121 -19
  71. package/src/plugins/Router.js +526 -181
  72. package/src/plugins/Store.js +448 -69
  73. package/src/plugins/index.js +1 -0
  74. package/types/core/Eleva.d.ts +263 -169
  75. package/types/core/Eleva.d.ts.map +1 -1
  76. package/types/index.d.cts +3 -0
  77. package/types/index.d.cts.map +1 -0
  78. package/types/index.d.ts +5 -0
  79. package/types/index.d.ts.map +1 -1
  80. package/types/modules/Emitter.d.ts +73 -30
  81. package/types/modules/Emitter.d.ts.map +1 -1
  82. package/types/modules/Renderer.d.ts +48 -18
  83. package/types/modules/Renderer.d.ts.map +1 -1
  84. package/types/modules/Signal.d.ts +44 -16
  85. package/types/modules/Signal.d.ts.map +1 -1
  86. package/types/modules/TemplateEngine.d.ts +46 -11
  87. package/types/modules/TemplateEngine.d.ts.map +1 -1
  88. package/types/plugins/Attr.d.ts +83 -16
  89. package/types/plugins/Attr.d.ts.map +1 -1
  90. package/types/plugins/Router.d.ts +498 -207
  91. package/types/plugins/Router.d.ts.map +1 -1
  92. package/types/plugins/Store.d.ts +211 -37
  93. package/types/plugins/Store.d.ts.map +1 -1
  94. package/dist/eleva-plugins.cjs.js.map +0 -1
  95. package/dist/eleva-plugins.esm.js.map +0 -1
  96. package/dist/eleva.cjs.js.map +0 -1
  97. package/dist/eleva.esm.js.map +0 -1
@@ -0,0 +1,1352 @@
1
+ import * as eleva from 'eleva';
2
+
3
+ declare namespace AttrPlugin {
4
+ let name: string;
5
+ let version: string;
6
+ let description: string;
7
+ /**
8
+ * Installs the plugin into the Eleva instance.
9
+ *
10
+ * @public
11
+ * Method wrapping behavior:
12
+ * - Stores original `_patchNode` in `renderer._originalPatchNode`
13
+ * - Overrides `renderer._patchNode` to use enhanced attribute handling
14
+ * - Adds `renderer.updateAttributes` and `eleva.updateElementAttributes` helpers
15
+ * - Call `uninstall()` to restore original behavior
16
+ *
17
+ * @param {Eleva} eleva - The Eleva instance to enhance.
18
+ * @param {AttrPluginOptions} options - Plugin configuration options.
19
+ * @param {boolean} [options.enableAria=true] - Enable ARIA attribute handling.
20
+ * Maps aria-* attributes to DOM properties (e.g., aria-expanded → ariaExpanded).
21
+ * @param {boolean} [options.enableData=true] - Enable data attribute handling.
22
+ * Syncs data-* attributes with element.dataset for consistent access.
23
+ * @param {boolean} [options.enableBoolean=true] - Enable boolean attribute handling.
24
+ * Treats empty strings and attribute names as true, "false" string as false.
25
+ * @param {boolean} [options.enableDynamic=true] - Enable dynamic property detection.
26
+ * Searches element prototype chain for property matches (useful for custom elements).
27
+ * @returns {void}
28
+ * @example
29
+ * // Basic installation with defaults
30
+ * app.use(AttrPlugin);
31
+ *
32
+ * @example
33
+ * // Custom configuration
34
+ * app.use(AttrPlugin, {
35
+ * enableAria: true,
36
+ * enableData: true,
37
+ * enableBoolean: true,
38
+ * enableDynamic: false // Disable for performance
39
+ * });
40
+ *
41
+ * @example
42
+ * // Using ARIA attributes in templates
43
+ * template: (ctx) => `
44
+ * <div role="dialog" aria-modal="true" aria-labelledby="title">
45
+ * <h2 id="title">Modal Title</h2>
46
+ * <button aria-expanded="${ctx.isOpen.value}">Toggle</button>
47
+ * </div>
48
+ * `
49
+ * @see uninstall - Remove the plugin and restore original behavior.
50
+ */
51
+ function install(eleva: Eleva$2, options?: AttrPluginOptions): void;
52
+ /**
53
+ * Uninstalls the plugin from the Eleva instance.
54
+ *
55
+ * @public
56
+ * @param {Eleva} eleva - The Eleva instance.
57
+ * @returns {void}
58
+ * @description
59
+ * Restores the original renderer patching behavior and removes
60
+ * `eleva.updateElementAttributes`.
61
+ * @example
62
+ * // Uninstall the plugin
63
+ * AttrPlugin.uninstall(app);
64
+ * @see install - Install the plugin.
65
+ */
66
+ function uninstall(eleva: Eleva$2): void;
67
+ }
68
+
69
+ /**
70
+ * Type imports from the Eleva core library.
71
+ */
72
+ type Eleva$2 = eleva.Eleva;
73
+ /**
74
+ * Configuration options for the AttrPlugin.
75
+ */
76
+ type AttrPluginOptions = {
77
+ /**
78
+ * Enable ARIA attribute handling.
79
+ */
80
+ enableAria?: boolean | undefined;
81
+ /**
82
+ * Enable data attribute handling.
83
+ */
84
+ enableData?: boolean | undefined;
85
+ /**
86
+ * Enable boolean attribute handling.
87
+ */
88
+ enableBoolean?: boolean | undefined;
89
+ /**
90
+ * Enable dynamic property detection.
91
+ */
92
+ enableDynamic?: boolean | undefined;
93
+ };
94
+
95
+ /**
96
+ * Interface for router plugins.
97
+ */
98
+ type RouterPlugin = {
99
+ /**
100
+ * Unique plugin identifier.
101
+ */
102
+ name: string;
103
+ /**
104
+ * Plugin version (recommended to match router version).
105
+ */
106
+ version?: string | undefined;
107
+ /**
108
+ * Installation function.
109
+ */
110
+ install: (router: Router, options?: Record<string, unknown>) => void;
111
+ /**
112
+ * Cleanup function called on router.destroy().
113
+ */
114
+ destroy?: ((router: Router) => void | Promise<void>) | undefined;
115
+ };
116
+ declare namespace RouterPlugin {
117
+ let name: string;
118
+ let version: string;
119
+ let description: string;
120
+ /**
121
+ * Installs the RouterPlugin into an Eleva instance.
122
+ *
123
+ * @public
124
+ * @param {Eleva} eleva - The Eleva instance.
125
+ * @param {RouterOptions} options - Router configuration options.
126
+ * @param {string} options.mount - A CSS selector for the main element where the app is mounted.
127
+ * @param {RouteDefinition[]} options.routes - An array of route definitions.
128
+ * @param {'hash' | 'query' | 'history'} [options.mode='hash'] - The routing mode.
129
+ * @param {string} [options.queryParam='view'] - The query parameter to use in 'query' mode.
130
+ * @param {string} [options.viewSelector='view'] - Base selector for the view element (matched as #id, .class, [data-*], or raw selector).
131
+ * @param {boolean} [options.autoStart=true] - Whether to start the router automatically.
132
+ * @param {NavigationGuard} [options.onBeforeEach] - A global guard executed before every navigation.
133
+ * @param {RouteComponent} [options.globalLayout] - A global layout for all routes.
134
+ * @returns {Router} The created router instance.
135
+ * @throws {Error} If 'mount' option is not provided.
136
+ * @throws {Error} If 'routes' option is not an array.
137
+ * @throws {Error} If component registration fails during route processing.
138
+ * @description
139
+ * Registers route/layout components, sets `eleva.router`, and adds helpers
140
+ * (`eleva.navigate`, `eleva.getCurrentRoute`, `eleva.getRouteParams`, `eleva.getRouteQuery`).
141
+ * When `autoStart` is enabled, startup is scheduled via microtask.
142
+ *
143
+ * @example
144
+ * // main.js
145
+ * import Eleva from 'eleva';
146
+ * import { RouterPlugin } from './plugins/RouterPlugin.js';
147
+ *
148
+ * const app = new Eleva('myApp');
149
+ *
150
+ * const HomePage = { template: () => `<h1>Home</h1>` };
151
+ * const AboutPage = { template: () => `<h1>About Us</h1>` };
152
+ *
153
+ * app.use(RouterPlugin, {
154
+ * mount: '#app',
155
+ * routes: [
156
+ * { path: '/', component: HomePage },
157
+ * { path: '/about', component: AboutPage }
158
+ * ]
159
+ * });
160
+ */
161
+ function install(eleva: Eleva$1, options?: RouterOptions): Router;
162
+ /**
163
+ * Uninstalls the plugin from the Eleva instance.
164
+ *
165
+ * @public
166
+ * @async
167
+ * @param {Eleva} eleva - The Eleva instance.
168
+ * @returns {Promise<void>}
169
+ * @description
170
+ * Destroys the router instance, removes `eleva.router`, and deletes helper methods
171
+ * (`eleva.navigate`, `eleva.getCurrentRoute`, `eleva.getRouteParams`, `eleva.getRouteQuery`).
172
+ */
173
+ function uninstall(eleva: Eleva$1): Promise<void>;
174
+ }
175
+
176
+ /**
177
+ * Type imports from the Eleva core library.
178
+ */
179
+ type Eleva$1 = eleva.Eleva;
180
+ /**
181
+ * Type imports from the Eleva core library.
182
+ */
183
+ type ComponentDefinition = eleva.ComponentDefinition;
184
+ /**
185
+ * Type imports from the Eleva core library.
186
+ */
187
+ type MountResult = eleva.MountResult;
188
+ /**
189
+ * Generic type import.
190
+ */
191
+ type Signal$1<T> = eleva.Signal<T>;
192
+ /**
193
+ * The routing mode determines how the router manages URL state.
194
+ * - `hash`: Uses URL hash (e.g., `/#/path`) - works without server config
195
+ * - `history`: Uses HTML5 History API (e.g., `/path`) - requires server config
196
+ * - `query`: Uses query parameters (e.g., `?view=/path`) - useful for embedded apps
197
+ */
198
+ type RouterMode = "hash" | "history" | "query";
199
+ /**
200
+ * Route parameters extracted from the URL path.
201
+ */
202
+ type RouteParams = Record<string, string>;
203
+ /**
204
+ * Query parameters from the URL query string.
205
+ */
206
+ type QueryParams = Record<string, string>;
207
+ /**
208
+ * Navigation input parameters supporting multiple value types.
209
+ */
210
+ type NavigationParams = Record<string, string | number | boolean>;
211
+ /**
212
+ * Router configuration options.
213
+ */
214
+ type RouterOptions = {
215
+ /**
216
+ * The routing mode to use.
217
+ */
218
+ mode?: RouterMode | undefined;
219
+ /**
220
+ * Query parameter name for 'query' mode.
221
+ */
222
+ queryParam?: string | undefined;
223
+ /**
224
+ * Base selector for the view element.
225
+ */
226
+ viewSelector?: string | undefined;
227
+ /**
228
+ * CSS selector for the mount point element.
229
+ */
230
+ mount: string;
231
+ /**
232
+ * Array of route definitions.
233
+ */
234
+ routes: RouteDefinition[];
235
+ /**
236
+ * Default layout for all routes.
237
+ */
238
+ globalLayout?: RouteComponent | undefined;
239
+ /**
240
+ * Global navigation guard.
241
+ */
242
+ onBeforeEach?: NavigationGuard | undefined;
243
+ /**
244
+ * Whether to start the router automatically.
245
+ */
246
+ autoStart?: boolean | undefined;
247
+ };
248
+ /**
249
+ * Object describing a navigation target for `router.navigate()`.
250
+ */
251
+ type NavigationTarget = {
252
+ /**
253
+ * The target path (can include params like '/users/:id').
254
+ */
255
+ path: string;
256
+ /**
257
+ * Route parameters to inject.
258
+ */
259
+ params?: NavigationParams | undefined;
260
+ /**
261
+ * Query parameters to append.
262
+ */
263
+ query?: NavigationParams | undefined;
264
+ /**
265
+ * Whether to replace current history entry.
266
+ */
267
+ replace?: boolean | undefined;
268
+ /**
269
+ * History state to pass.
270
+ */
271
+ state?: unknown;
272
+ };
273
+ /**
274
+ * Internal representation of a parsed route path segment.
275
+ */
276
+ type RouteSegment = {
277
+ /**
278
+ * The segment type.
279
+ */
280
+ type: "static" | "param";
281
+ /**
282
+ * The segment value (static segments).
283
+ */
284
+ value?: string | undefined;
285
+ /**
286
+ * The parameter name (param segments).
287
+ */
288
+ name?: string | undefined;
289
+ };
290
+ /**
291
+ * Arbitrary metadata attached to routes for use in guards and components.
292
+ */
293
+ type RouteMeta = Record<string, unknown>;
294
+ /**
295
+ * Interface for the router's error handling system.
296
+ */
297
+ type RouterErrorHandler = {
298
+ /**
299
+ * Throws a formatted error.
300
+ */
301
+ handle: (error: Error, context: string, details?: Record<string, unknown>) => void;
302
+ /**
303
+ * Logs a warning.
304
+ */
305
+ warn: (message: string, details?: Record<string, unknown>) => void;
306
+ /**
307
+ * Logs an error without throwing.
308
+ */
309
+ log: (message: string, error: Error, details?: Record<string, unknown>) => void;
310
+ };
311
+ /**
312
+ * Represents the current or target location in the router.
313
+ */
314
+ type RouteLocation = {
315
+ /**
316
+ * The path of the route (e.g., '/users/123').
317
+ */
318
+ path: string;
319
+ /**
320
+ * Query parameters as key-value pairs.
321
+ */
322
+ query: QueryParams;
323
+ /**
324
+ * The routed URL string (path plus query).
325
+ */
326
+ fullUrl: string;
327
+ /**
328
+ * Dynamic route parameters.
329
+ */
330
+ params: RouteParams;
331
+ /**
332
+ * Metadata associated with the matched route.
333
+ */
334
+ meta: RouteMeta;
335
+ /**
336
+ * The optional name of the matched route.
337
+ */
338
+ name?: string | undefined;
339
+ /**
340
+ * The raw route definition that was matched.
341
+ */
342
+ matched: RouteDefinition;
343
+ };
344
+ /**
345
+ * Return value of a navigation guard.
346
+ * - `true` or `undefined/void`: Allow navigation
347
+ * - `false`: Abort navigation
348
+ * - `string`: Redirect to path
349
+ * - `NavigationTarget`: Redirect with options
350
+ */
351
+ type NavigationGuardResult = boolean | string | NavigationTarget | void;
352
+ /**
353
+ * Navigation guard function that controls navigation flow.
354
+ */
355
+ type NavigationGuard = (to: RouteLocation, from: RouteLocation | null) => NavigationGuardResult | Promise<NavigationGuardResult>;
356
+ /**
357
+ * Navigation hook for side effects. Does not affect navigation flow.
358
+ */
359
+ type NavigationHook = (to: RouteLocation, from: RouteLocation | null) => void | Promise<void>;
360
+ /**
361
+ * A component that can be rendered for a route.
362
+ * - `string`: Name of a registered component
363
+ * - `ComponentDefinition`: Inline component definition
364
+ * - `() => ComponentDefinition`: Factory function returning a component
365
+ * - `() => Promise<ComponentDefinition>`: Async factory function
366
+ * - `() => Promise<{default: ComponentDefinition}>`: Lazy-loaded module (e.g., `() => import('./Page.js')`)
367
+ */
368
+ type RouteComponent = string | ComponentDefinition | (() => ComponentDefinition | Promise<ComponentDefinition | {
369
+ default: ComponentDefinition;
370
+ }>);
371
+ /**
372
+ * Defines a route in the application.
373
+ */
374
+ type RouteDefinition = {
375
+ /**
376
+ * URL path pattern. Supports:
377
+ * - Static: '/about'
378
+ * - Dynamic params: '/users/:id'
379
+ * - Wildcard: '*' (catch-all, conventionally last)
380
+ */
381
+ path: string;
382
+ /**
383
+ * The component to render for this route.
384
+ */
385
+ component: RouteComponent;
386
+ /**
387
+ * Optional layout component to wrap the route component.
388
+ */
389
+ layout?: RouteComponent | undefined;
390
+ /**
391
+ * Optional route name for programmatic navigation.
392
+ */
393
+ name?: string | undefined;
394
+ /**
395
+ * Optional metadata (auth flags, titles, etc.).
396
+ */
397
+ meta?: RouteMeta | undefined;
398
+ /**
399
+ * Route-specific guard before entering.
400
+ */
401
+ beforeEnter?: NavigationGuard | undefined;
402
+ /**
403
+ * Hook after entering and component is mounted.
404
+ */
405
+ afterEnter?: NavigationHook | undefined;
406
+ /**
407
+ * Guard before leaving this route.
408
+ */
409
+ beforeLeave?: NavigationGuard | undefined;
410
+ /**
411
+ * Hook after leaving and component is unmounted.
412
+ */
413
+ afterLeave?: NavigationHook | undefined;
414
+ /**
415
+ * Internal: parsed path segments (added by router).
416
+ */
417
+ segments?: RouteSegment[] | undefined;
418
+ };
419
+ /**
420
+ * Represents the current or target location in the router.
421
+ * @typedef {Object} RouteLocation
422
+ * @property {string} path
423
+ * The path of the route (e.g., '/users/123').
424
+ * @property {QueryParams} query
425
+ * Query parameters as key-value pairs.
426
+ * @property {string} fullUrl
427
+ * The routed URL string (path plus query).
428
+ * @property {RouteParams} params
429
+ * Dynamic route parameters.
430
+ * @property {RouteMeta} meta
431
+ * Metadata associated with the matched route.
432
+ * @property {string} [name]
433
+ * The optional name of the matched route.
434
+ * @property {RouteDefinition} matched
435
+ * The raw route definition that was matched.
436
+ * @description Represents the current or target location in the router.
437
+ */
438
+ /**
439
+ * Return value of a navigation guard.
440
+ * - `true` or `undefined/void`: Allow navigation
441
+ * - `false`: Abort navigation
442
+ * - `string`: Redirect to path
443
+ * - `NavigationTarget`: Redirect with options
444
+ * @typedef {boolean | string | NavigationTarget | void} NavigationGuardResult
445
+ */
446
+ /**
447
+ * Navigation guard function that controls navigation flow.
448
+ * @callback NavigationGuard
449
+ * @param {RouteLocation} to
450
+ * The target route location.
451
+ * @param {RouteLocation | null} from
452
+ * The source route location (null on initial).
453
+ * @returns {NavigationGuardResult | Promise<NavigationGuardResult>}
454
+ * @description A function that controls navigation flow. Runs before navigation is confirmed.
455
+ * @example
456
+ * // Simple auth guard
457
+ * const authGuard = (to, from) => {
458
+ * if (to.meta.requiresAuth && !isLoggedIn()) {
459
+ * return '/login'; // Redirect
460
+ * }
461
+ * // Allow navigation (implicit return undefined)
462
+ * };
463
+ */
464
+ /**
465
+ * Navigation hook for side effects. Does not affect navigation flow.
466
+ * @callback NavigationHook
467
+ * @param {RouteLocation} to
468
+ * The target route location.
469
+ * @param {RouteLocation | null} from
470
+ * The source route location.
471
+ * @returns {void | Promise<void>}
472
+ * @description A lifecycle hook for side effects. Does not affect navigation flow.
473
+ * @example
474
+ * // Analytics hook
475
+ * const analyticsHook = (to, from) => {
476
+ * analytics.trackPageView(to.path);
477
+ * };
478
+ */
479
+ /**
480
+ * Interface for router plugins.
481
+ * @typedef {Object} RouterPlugin
482
+ * @property {string} name
483
+ * Unique plugin identifier.
484
+ * @property {string} [version]
485
+ * Plugin version (recommended to match router version).
486
+ * @property {(router: Router, options?: Record<string, unknown>) => void} install
487
+ * Installation function.
488
+ * @property {(router: Router) => void | Promise<void>} [destroy]
489
+ * Cleanup function called on router.destroy().
490
+ * @description Interface for router plugins. Plugins can extend router functionality.
491
+ * @example
492
+ * const AnalyticsPlugin = {
493
+ * name: 'analytics',
494
+ * version: '1.0.0',
495
+ * install(router, options) {
496
+ * router.emitter.on('router:afterEach', (to, from) => {
497
+ * analytics.track(to.path);
498
+ * });
499
+ * }
500
+ * };
501
+ */
502
+ /**
503
+ * Context object for navigation events that plugins can modify.
504
+ * @typedef {Object} NavigationContext
505
+ * @property {RouteLocation} to
506
+ * The target route location.
507
+ * @property {RouteLocation | null} from
508
+ * The source route location.
509
+ * @property {boolean} cancelled
510
+ * Whether navigation has been cancelled.
511
+ * @property {string | NavigationTarget | null} redirectTo
512
+ * Redirect target if set.
513
+ * @description Passed to navigation events. Plugins can modify to control navigation flow.
514
+ */
515
+ /**
516
+ * Context object for component resolution events.
517
+ * @typedef {Object} ResolveContext
518
+ * @property {RouteLocation} to
519
+ * The target route location.
520
+ * @property {RouteLocation | null} from
521
+ * The source route location.
522
+ * @property {RouteDefinition} route
523
+ * The matched route definition.
524
+ * @property {ComponentDefinition | null} layoutComponent
525
+ * The resolved layout component (available in afterResolve).
526
+ * @property {ComponentDefinition | null} pageComponent
527
+ * The resolved page component (available in afterResolve).
528
+ * @property {boolean} cancelled
529
+ * Whether navigation has been cancelled.
530
+ * @property {string | NavigationTarget | null} redirectTo
531
+ * Redirect target if set.
532
+ * @description Passed to component resolution events.
533
+ */
534
+ /**
535
+ * Context object for render events.
536
+ * @typedef {Object} RenderContext
537
+ * @property {RouteLocation} to
538
+ * The target route location.
539
+ * @property {RouteLocation | null} from
540
+ * The source route location.
541
+ * @property {ComponentDefinition | null} layoutComponent
542
+ * The layout component being rendered.
543
+ * @property {ComponentDefinition} pageComponent
544
+ * The page component being rendered.
545
+ * @description Passed to render events.
546
+ */
547
+ /**
548
+ * Context object for scroll events.
549
+ * @typedef {Object} ScrollContext
550
+ * @property {RouteLocation} to
551
+ * The target route location.
552
+ * @property {RouteLocation | null} from
553
+ * The source route location.
554
+ * @property {{x: number, y: number} | null} savedPosition
555
+ * Saved position (back/forward nav).
556
+ * @description Passed to scroll events for plugins to handle scroll behavior.
557
+ */
558
+ /**
559
+ * A component that can be rendered for a route.
560
+ * - `string`: Name of a registered component
561
+ * - `ComponentDefinition`: Inline component definition
562
+ * - `() => ComponentDefinition`: Factory function returning a component
563
+ * - `() => Promise<ComponentDefinition>`: Async factory function
564
+ * - `() => Promise<{default: ComponentDefinition}>`: Lazy-loaded module (e.g., `() => import('./Page.js')`)
565
+ * @typedef {string | ComponentDefinition | (() => ComponentDefinition | Promise<ComponentDefinition | {default: ComponentDefinition}>)} RouteComponent
566
+ */
567
+ /**
568
+ * Defines a route in the application.
569
+ * @typedef {Object} RouteDefinition
570
+ * @property {string} path
571
+ * URL path pattern. Supports:
572
+ * - Static: '/about'
573
+ * - Dynamic params: '/users/:id'
574
+ * - Wildcard: '*' (catch-all, conventionally last)
575
+ * @property {RouteComponent} component
576
+ * The component to render for this route.
577
+ * @property {RouteComponent} [layout]
578
+ * Optional layout component to wrap the route component.
579
+ * @property {string} [name]
580
+ * Optional route name for programmatic navigation.
581
+ * @property {RouteMeta} [meta]
582
+ * Optional metadata (auth flags, titles, etc.).
583
+ * @property {NavigationGuard} [beforeEnter]
584
+ * Route-specific guard before entering.
585
+ * @property {NavigationHook} [afterEnter]
586
+ * Hook after entering and component is mounted.
587
+ * @property {NavigationGuard} [beforeLeave]
588
+ * Guard before leaving this route.
589
+ * @property {NavigationHook} [afterLeave]
590
+ * Hook after leaving and component is unmounted.
591
+ * @property {RouteSegment[]} [segments]
592
+ * Internal: parsed path segments (added by router).
593
+ * @description Defines a route in the application.
594
+ * @note Nested routes are not supported. Use shared layouts with flat routes instead.
595
+ * @example
596
+ * // Static route
597
+ * { path: '/about', component: AboutPage }
598
+ *
599
+ * // Dynamic route with params
600
+ * { path: '/users/:id', component: UserPage, meta: { requiresAuth: true } }
601
+ *
602
+ * // Lazy-loaded route with layout
603
+ * {
604
+ * path: '/dashboard',
605
+ * component: () => import('./Dashboard.js'),
606
+ * layout: DashboardLayout,
607
+ * beforeEnter: (to, from) => isLoggedIn() || '/login'
608
+ * }
609
+ *
610
+ * // Catch-all 404 route (conventionally last)
611
+ * { path: '*', component: NotFoundPage }
612
+ */
613
+ /**
614
+ * @class 🛤️ Router
615
+ * @classdesc A powerful, reactive, and flexible Router Plugin for Eleva.
616
+ * This class manages all routing logic, including state, navigation, and rendering.
617
+ *
618
+ * ## Features
619
+ * - Multiple routing modes (hash, history, query)
620
+ * - Reactive route state via Signals
621
+ * - Navigation guards and lifecycle hooks
622
+ * - Lazy-loaded components
623
+ * - Layout system
624
+ * - Plugin architecture
625
+ * - Scroll position management
626
+ *
627
+ * ## Events Reference
628
+ * | Event | Callback Type | Can Block | Description |
629
+ * |-------|--------------|-----------|-------------|
630
+ * | `router:ready` | {@link RouterReadyCallback} | No | Router initialized |
631
+ * | `router:beforeEach` | {@link NavigationContextCallback} | Yes | Before guards run |
632
+ * | `router:beforeResolve` | {@link ResolveContextCallback} | Yes | Before component loading |
633
+ * | `router:afterResolve` | {@link ResolveContextCallback} | No | After components loaded |
634
+ * | `router:afterLeave` | {@link RouteChangeCallback} | No | After leaving route |
635
+ * | `router:beforeRender` | {@link RenderContextCallback} | No | Before DOM update |
636
+ * | `router:afterRender` | {@link RenderContextCallback} | No | After DOM update |
637
+ * | `router:scroll` | {@link ScrollContextCallback} | No | For scroll behavior |
638
+ * | `router:afterEnter` | {@link RouteChangeCallback} | No | After entering route |
639
+ * | `router:afterEach` | {@link RouteChangeCallback} | No | Navigation complete |
640
+ * | `router:error` | {@link RouterErrorCallback} | No | Navigation error |
641
+ * | `router:routeAdded` | {@link RouteAddedCallback} | No | Dynamic route added |
642
+ * | `router:routeRemoved` | {@link RouteRemovedCallback} | No | Dynamic route removed |
643
+ *
644
+ * ## Reactive Signals
645
+ * - `currentRoute: Signal<RouteLocation | null>` - Current route info
646
+ * - `previousRoute: Signal<RouteLocation | null>` - Previous route info
647
+ * - `currentParams: Signal<RouteParams>` - Current route params
648
+ * - `currentQuery: Signal<QueryParams>` - Current query params
649
+ * - `currentLayout: Signal<MountResult | null>` - Mounted layout instance
650
+ * - `currentView: Signal<MountResult | null>` - Mounted view instance
651
+ * - `isReady: Signal<boolean>` - Router readiness state
652
+ *
653
+ * @note Internal API Access Policy:
654
+ * As a core Eleva plugin, the Router may access internal Eleva APIs (prefixed with _)
655
+ * such as `eleva._components`. This is intentional and these internal APIs are
656
+ * considered stable for official plugins. Third-party plugins should avoid
657
+ * accessing internal APIs as they may change without notice.
658
+ *
659
+ * @example
660
+ * // Basic setup
661
+ * const router = new Router(eleva, {
662
+ * mode: 'hash',
663
+ * mount: '#app',
664
+ * routes: [
665
+ * { path: '/', component: HomePage },
666
+ * { path: '/users/:id', component: UserPage },
667
+ * { path: '*', component: NotFoundPage }
668
+ * ]
669
+ * });
670
+ *
671
+ * // Start router
672
+ * await router.start();
673
+ *
674
+ * // Navigate programmatically
675
+ * const success = await router.navigate('/users/123');
676
+ *
677
+ * // Watch for route changes
678
+ * router.currentRoute.watch((route) => {
679
+ * document.title = route?.meta?.title || 'My App';
680
+ * });
681
+ *
682
+ * @private
683
+ */
684
+ declare class Router {
685
+ /**
686
+ * Creates an instance of the Router.
687
+ * @param {Eleva} eleva - The Eleva framework instance.
688
+ * @param {RouterOptions} options - The configuration options for the router.
689
+ * @throws {Error} If the routing mode is invalid.
690
+ */
691
+ constructor(eleva: Eleva$1, options?: RouterOptions);
692
+ /** @type {Eleva} The Eleva framework instance. */
693
+ eleva: Eleva$1;
694
+ /** @type {RouterOptions} The merged router options. */
695
+ options: RouterOptions;
696
+ /** @private @type {RouteDefinition[]} The processed list of route definitions. */
697
+ private routes;
698
+ /** @private @type {Emitter} The shared Eleva event emitter for global hooks. */
699
+ private emitter;
700
+ /** @private @type {boolean} A flag indicating if the router has been started. */
701
+ private isStarted;
702
+ /** @private @type {boolean} A flag to prevent navigation loops from history events. */
703
+ private _isNavigating;
704
+ /** @private @type {number} Counter for tracking navigation operations to prevent race conditions. */
705
+ private _navigationId;
706
+ /** @private @type {UnsubscribeFunction[]} A collection of cleanup functions for event listeners. */
707
+ private eventListeners;
708
+ /** @type {Signal<RouteLocation | null>} A reactive signal holding the current route's information. */
709
+ currentRoute: Signal$1<RouteLocation | null>;
710
+ /** @type {Signal<RouteLocation | null>} A reactive signal holding the previous route's information. */
711
+ previousRoute: Signal$1<RouteLocation | null>;
712
+ /** @type {Signal<RouteParams>} A reactive signal holding the current route's parameters. */
713
+ currentParams: Signal$1<RouteParams>;
714
+ /** @type {Signal<QueryParams>} A reactive signal holding the current route's query parameters. */
715
+ currentQuery: Signal$1<QueryParams>;
716
+ /** @type {Signal<MountResult | null>} A reactive signal for the currently mounted layout instance. */
717
+ currentLayout: Signal$1<MountResult | null>;
718
+ /** @type {Signal<MountResult | null>} A reactive signal for the currently mounted view (page) instance. */
719
+ currentView: Signal$1<MountResult | null>;
720
+ /** @type {Signal<boolean>} A reactive signal indicating if the router is ready (started and initial navigation complete). */
721
+ isReady: Signal$1<boolean>;
722
+ /** @private @type {Map<string, RouterPlugin>} Map of registered plugins by name. */
723
+ private plugins;
724
+ /** @private @type {NavigationGuard[]} Array of global before-each navigation guards. */
725
+ private _beforeEachGuards;
726
+ /** @type {RouterErrorHandler} The error handler instance. Can be overridden by plugins. */
727
+ errorHandler: RouterErrorHandler;
728
+ /** @private @type {Map<string, {x: number, y: number}>} Saved scroll positions by route path. */
729
+ private _scrollPositions;
730
+ /**
731
+ * Validates the provided router options.
732
+ * @private
733
+ * @throws {Error} If the routing mode is invalid.
734
+ */
735
+ private _validateOptions;
736
+ /**
737
+ * Pre-processes route definitions to parse their path segments for efficient matching.
738
+ * @private
739
+ * @param {RouteDefinition[]} routes - The raw route definitions.
740
+ * @returns {RouteDefinition[]} The processed routes.
741
+ */
742
+ private _processRoutes;
743
+ /**
744
+ * Parses a route path string into an array of static and parameter segments.
745
+ * @private
746
+ * @param {string} path - The path pattern to parse.
747
+ * @returns {{type: 'static' | 'param', value?: string, name?: string}[]} An array of segment objects.
748
+ * @throws {Error} If the route path is not a valid string.
749
+ */
750
+ private _parsePathIntoSegments;
751
+ /**
752
+ * Finds the view element within a container using multiple selector strategies.
753
+ * @private
754
+ * @param {HTMLElement} container - The parent element to search within.
755
+ * @returns {HTMLElement} The found view element or the container itself as a fallback.
756
+ */
757
+ private _findViewElement;
758
+ /**
759
+ * Starts the router, initializes event listeners, and performs the initial navigation.
760
+ * @returns {Promise<Router>} The router instance for method chaining.
761
+ * @listens window:hashchange In hash mode, triggers route changes.
762
+ * @listens window:popstate In history/query mode, triggers route changes.
763
+ * @emits router:ready When initialization completes successfully.
764
+ * @see destroy - Stop the router and clean up listeners.
765
+ * @see navigate - Programmatically navigate to a route.
766
+ *
767
+ * @example
768
+ * // Basic usage
769
+ * await router.start();
770
+ *
771
+ * // Method chaining
772
+ * await router.start().then(r => r.navigate('/home'));
773
+ *
774
+ * // Reactive readiness
775
+ * router.isReady.watch((ready) => {
776
+ * if (ready) console.log('Router is ready!');
777
+ * });
778
+ */
779
+ start(): Promise<Router>;
780
+ /**
781
+ * Stops the router and cleans up event listeners.
782
+ * Unmounts the current layout instance if present.
783
+ * @async
784
+ * @returns {Promise<void>}
785
+ * @see start - Restart the router after destroying.
786
+ */
787
+ destroy(): Promise<void>;
788
+ /**
789
+ * Alias for destroy(). Stops the router and cleans up all resources.
790
+ * Provided for semantic consistency (start/stop pattern).
791
+ * @async
792
+ * @returns {Promise<void>}
793
+ *
794
+ * @example
795
+ * await router.start();
796
+ * // ... later
797
+ * await router.stop();
798
+ */
799
+ stop(): Promise<void>;
800
+ /**
801
+ * Programmatically navigates to a new route.
802
+ * @async
803
+ * @param {string | NavigationTarget} location - The target location as a path string or navigation target object.
804
+ * @param {NavigationParams} [params] - Route parameters (only used when location is a string).
805
+ * @returns {Promise<boolean>} True if navigation succeeded, false if blocked by guards or failed.
806
+ * @emits router:error When navigation fails due to an exception.
807
+ * @see start - Initialize the router before navigating.
808
+ * @see currentRoute - Access the current route after navigation.
809
+ *
810
+ * @example
811
+ * // Basic navigation
812
+ * await router.navigate('/users/123');
813
+ *
814
+ * // Check if navigation succeeded
815
+ * const success = await router.navigate('/protected');
816
+ * if (!success) {
817
+ * console.log('Navigation was blocked by a guard');
818
+ * }
819
+ *
820
+ * // Navigate with options
821
+ * await router.navigate({
822
+ * path: '/users/:id',
823
+ * params: { id: '123' },
824
+ * query: { tab: 'profile' },
825
+ * replace: true
826
+ * });
827
+ */
828
+ navigate(location: string | NavigationTarget, params?: NavigationParams): Promise<boolean>;
829
+ /**
830
+ * Builds a URL for query mode.
831
+ * @private
832
+ * @param {string} path - The path to set as the query parameter.
833
+ * @returns {string} The full URL with the updated query string.
834
+ */
835
+ private _buildQueryUrl;
836
+ /**
837
+ * Checks if the target route is identical to the current route.
838
+ * @private
839
+ * @param {string} path - The target path with query string.
840
+ * @param {object} params - The target params.
841
+ * @param {object} query - The target query.
842
+ * @returns {boolean} True if the routes are the same.
843
+ */
844
+ private _isSameRoute;
845
+ /**
846
+ * Injects dynamic parameters into a path string.
847
+ * Replaces `:param` placeholders with URL-encoded values from the params object.
848
+ *
849
+ * @private
850
+ * @param {string} path - The path pattern containing `:param` placeholders.
851
+ * @param {RouteParams} params - Key-value pairs to inject into the path.
852
+ * @returns {string} The path with all parameters replaced.
853
+ *
854
+ * @example
855
+ * this._buildPath('/users/:id/posts/:postId', { id: '123', postId: '456' });
856
+ * // Returns: '/users/123/posts/456'
857
+ */
858
+ private _buildPath;
859
+ /**
860
+ * The handler for browser-initiated route changes (e.g., back/forward buttons).
861
+ *
862
+ * @private
863
+ * @async
864
+ * @param {boolean} [isPopState=true] - Whether this is a popstate event (back/forward navigation).
865
+ * @returns {Promise<void>}
866
+ * @emits router:error When route change handling fails.
867
+ */
868
+ private _handleRouteChange;
869
+ /**
870
+ * Manages the core navigation lifecycle. Runs guards before committing changes.
871
+ *
872
+ * @private
873
+ * @async
874
+ * @param {string} fullPath - The full path (e.g., '/users/123?foo=bar') to navigate to.
875
+ * @param {boolean} [isPopState=false] - Whether this navigation was triggered by popstate (back/forward).
876
+ * @returns {Promise<boolean>} `true` if navigation succeeded, `false` if aborted.
877
+ * @emits router:notFound When no matching route is found.
878
+ * @emits router:beforeResolve Before component resolution (can block/redirect).
879
+ * @emits router:afterResolve After components are resolved.
880
+ * @emits router:afterLeave After leaving the previous route.
881
+ * @emits router:beforeRender Before DOM rendering.
882
+ * @emits router:afterRender After DOM rendering completes.
883
+ * @emits router:scroll After render, for scroll behavior handling.
884
+ * @emits router:afterEnter After entering the new route.
885
+ * @emits router:afterEach After navigation completes successfully.
886
+ * @emits router:error When an error occurs during navigation.
887
+ * @see _runGuards - Guard execution.
888
+ * @see _resolveComponents - Component resolution.
889
+ * @see _render - DOM rendering.
890
+ */
891
+ private _proceedWithNavigation;
892
+ /**
893
+ * Executes all applicable navigation guards for a transition in order.
894
+ * Guards are executed in the following order:
895
+ * 1. Global beforeEach event (emitter-based, can block via context)
896
+ * 2. Global beforeEach guards (registered via onBeforeEach)
897
+ * 3. Route-specific beforeLeave guard (from the route being left)
898
+ * 4. Route-specific beforeEnter guard (from the route being entered)
899
+ *
900
+ * @private
901
+ * @param {RouteLocation} to - The target route location.
902
+ * @param {RouteLocation | null} from - The current route location (null on initial navigation).
903
+ * @param {RouteDefinition} route - The matched route definition.
904
+ * @returns {Promise<boolean>} `false` if navigation should be aborted.
905
+ * @emits router:beforeEach Before guards run (can block/redirect via context).
906
+ */
907
+ private _runGuards;
908
+ /**
909
+ * Resolves a string component definition to a component object.
910
+ * @private
911
+ * @param {string} def - The component name to resolve.
912
+ * @returns {ComponentDefinition} The resolved component.
913
+ * @throws {Error} If the component is not registered.
914
+ *
915
+ * @note Core plugins (Router, Attr, Store) may access eleva._components
916
+ * directly. This is intentional and stable for official Eleva plugins shipped
917
+ * with the framework. Third-party plugins should use eleva.component() for
918
+ * registration and avoid direct access to internal APIs.
919
+ */
920
+ private _resolveStringComponent;
921
+ /**
922
+ * Resolves a function component definition to a component object.
923
+ * @private
924
+ * @async
925
+ * @param {() => ComponentDefinition | Promise<ComponentDefinition | { default: ComponentDefinition }>} def - The function to resolve.
926
+ * @returns {Promise<ComponentDefinition>} The resolved component.
927
+ * @throws {Error} If the function fails to load the component.
928
+ */
929
+ private _resolveFunctionComponent;
930
+ /**
931
+ * Validates a component definition object.
932
+ * @private
933
+ * @param {unknown} def - The component definition to validate.
934
+ * @returns {ComponentDefinition} The validated component.
935
+ * @throws {Error} If the component definition is invalid.
936
+ */
937
+ private _validateComponentDefinition;
938
+ /**
939
+ * Resolves a component definition to a component object.
940
+ * @private
941
+ * @param {unknown} def - The component definition to resolve.
942
+ * @returns {Promise<ComponentDefinition | null>} The resolved component or null.
943
+ */
944
+ private _resolveComponent;
945
+ /**
946
+ * Asynchronously resolves the layout and page components for a route.
947
+ * @private
948
+ * @async
949
+ * @param {RouteDefinition} route - The route to resolve components for.
950
+ * @returns {Promise<{layoutComponent: ComponentDefinition | null, pageComponent: ComponentDefinition}>}
951
+ * @throws {Error} If page component cannot be resolved.
952
+ */
953
+ private _resolveComponents;
954
+ /**
955
+ * Renders the components for the current route into the DOM.
956
+ *
957
+ * Rendering algorithm:
958
+ * 1. Find the mount element using options.mount selector
959
+ * 2. If layoutComponent exists:
960
+ * a. Mount layout to mount element
961
+ * b. Find view element within layout (using viewSelector)
962
+ * c. Mount page component to view element
963
+ * 3. If no layoutComponent:
964
+ * a. Mount page component directly to mount element
965
+ * b. Set currentLayout to null
966
+ *
967
+ * @private
968
+ * @async
969
+ * @param {ComponentDefinition | null} layoutComponent - The pre-loaded layout component.
970
+ * @param {ComponentDefinition} pageComponent - The pre-loaded page component.
971
+ * @returns {Promise<void>}
972
+ * @throws {Error} If mount element is not found in the DOM.
973
+ * @throws {Error} If component mounting fails (propagated from eleva.mount).
974
+ */
975
+ private _render;
976
+ /**
977
+ * Creates a getter function for router context properties.
978
+ * @private
979
+ * @param {string} property - The property name to access.
980
+ * @param {unknown} defaultValue - The default value if property is undefined.
981
+ * @returns {() => unknown} A getter function.
982
+ */
983
+ private _createRouteGetter;
984
+ /**
985
+ * Wraps a component definition to inject router-specific context into its setup function.
986
+ * @private
987
+ * @param {ComponentDefinition} component - The component to wrap.
988
+ * @returns {ComponentDefinition} The wrapped component definition.
989
+ */
990
+ private _wrapComponent;
991
+ /**
992
+ * Recursively wraps all child components to ensure they have access to router context.
993
+ * String component references are returned as-is (context injected during mount).
994
+ * Objects are wrapped with router context and their children are recursively wrapped.
995
+ *
996
+ * @private
997
+ * @param {ComponentDefinition | string} component - The component to wrap (can be a definition object or a registered component name).
998
+ * @returns {ComponentDefinition | string} The wrapped component definition or the original string reference.
999
+ * @see _wrapComponent - Single component wrapping.
1000
+ */
1001
+ private _wrapComponentWithChildren;
1002
+ /**
1003
+ * Gets the current location information from the browser's window object.
1004
+ * @private
1005
+ * @returns {Omit<RouteLocation, 'params' | 'meta' | 'name' | 'matched'>}
1006
+ */
1007
+ private _getCurrentLocation;
1008
+ /**
1009
+ * Parses a query string into a key-value object.
1010
+ * Uses URLSearchParams for robust parsing of encoded values.
1011
+ *
1012
+ * @private
1013
+ * @param {string} queryString - The query string to parse (without leading '?').
1014
+ * @returns {QueryParams} Key-value pairs from the query string.
1015
+ *
1016
+ * @example
1017
+ * this._parseQuery('foo=bar&baz=qux');
1018
+ * // Returns: { foo: 'bar', baz: 'qux' }
1019
+ */
1020
+ private _parseQuery;
1021
+ /**
1022
+ * Matches a given path against the registered routes.
1023
+ * @private
1024
+ * @param {string} path - The path to match.
1025
+ * @returns {{route: RouteDefinition, params: Object<string, string>} | null} The matched route and its params, or null.
1026
+ */
1027
+ private _matchRoute;
1028
+ /**
1029
+ * Adds a new route dynamically at runtime.
1030
+ * The route will be processed and available for navigation immediately.
1031
+ * Routes are inserted before the wildcard (*) route if one exists.
1032
+ *
1033
+ * @param {RouteDefinition} route - The route definition to add.
1034
+ * @param {RouteDefinition} [parentRoute] - Optional parent route to add as a child (not yet implemented).
1035
+ * @returns {() => void} A function to remove the added route (returns no-op if route was invalid).
1036
+ * @emits router:routeAdded When a route is successfully added.
1037
+ *
1038
+ * @example
1039
+ * // Add a route dynamically
1040
+ * const removeRoute = router.addRoute({
1041
+ * path: '/dynamic',
1042
+ * component: DynamicPage,
1043
+ * meta: { title: 'Dynamic Page' }
1044
+ * });
1045
+ *
1046
+ * // Later, remove the route
1047
+ * removeRoute();
1048
+ */
1049
+ addRoute(route: RouteDefinition, parentRoute?: RouteDefinition): () => void;
1050
+ /**
1051
+ * Removes a route by its path.
1052
+ *
1053
+ * @param {string} path - The path of the route to remove.
1054
+ * @returns {boolean} True if the route was removed, false if not found.
1055
+ * @emits router:routeRemoved When a route is successfully removed.
1056
+ *
1057
+ * @example
1058
+ * router.removeRoute('/dynamic');
1059
+ */
1060
+ removeRoute(path: string): boolean;
1061
+ /**
1062
+ * Checks if a route with the given path exists.
1063
+ *
1064
+ * @param {string} path - The path to check.
1065
+ * @returns {boolean} True if the route exists.
1066
+ *
1067
+ * @example
1068
+ * if (router.hasRoute('/users/:id')) {
1069
+ * console.log('User route exists');
1070
+ * }
1071
+ */
1072
+ hasRoute(path: string): boolean;
1073
+ /**
1074
+ * Gets all registered routes.
1075
+ *
1076
+ * @returns {RouteDefinition[]} A copy of the routes array.
1077
+ *
1078
+ * @example
1079
+ * const routes = router.getRoutes();
1080
+ * console.log('Available routes:', routes.map(r => r.path));
1081
+ */
1082
+ getRoutes(): RouteDefinition[];
1083
+ /**
1084
+ * Gets a route by its path.
1085
+ *
1086
+ * @param {string} path - The path of the route to get.
1087
+ * @returns {RouteDefinition | undefined} The route definition or undefined.
1088
+ *
1089
+ * @example
1090
+ * const route = router.getRoute('/users/:id');
1091
+ * if (route) {
1092
+ * console.log('Route meta:', route.meta);
1093
+ * }
1094
+ */
1095
+ getRoute(path: string): RouteDefinition | undefined;
1096
+ /**
1097
+ * Registers a global pre-navigation guard.
1098
+ * Multiple guards can be registered and will be executed in order.
1099
+ * Guards can also be registered via the emitter using `router:beforeEach` event.
1100
+ *
1101
+ * @param {NavigationGuard} guard - The guard function to register.
1102
+ * @returns {() => void} A function to unregister the guard.
1103
+ *
1104
+ * @example
1105
+ * // Register a guard
1106
+ * const unregister = router.onBeforeEach((to, from) => {
1107
+ * if (to.meta.requiresAuth && !isAuthenticated()) {
1108
+ * return '/login';
1109
+ * }
1110
+ * });
1111
+ *
1112
+ * // Later, unregister the guard
1113
+ * unregister();
1114
+ */
1115
+ onBeforeEach(guard: NavigationGuard): () => void;
1116
+ /**
1117
+ * Registers a global hook that runs after a new route component has been mounted.
1118
+ * @param {NavigationHook} hook - The hook function to register.
1119
+ * @returns {() => void} A function to unregister the hook.
1120
+ * @listens router:afterEnter
1121
+ */
1122
+ onAfterEnter(hook: NavigationHook): () => void;
1123
+ /**
1124
+ * Registers a global hook that runs after a route component has been unmounted.
1125
+ * @param {NavigationHook} hook - The hook function to register.
1126
+ * @returns {() => void} A function to unregister the hook.
1127
+ * @listens router:afterLeave
1128
+ */
1129
+ onAfterLeave(hook: NavigationHook): () => void;
1130
+ /**
1131
+ * Registers a global hook that runs after a navigation has been confirmed and all hooks have completed.
1132
+ * @param {NavigationHook} hook - The hook function to register.
1133
+ * @returns {() => void} A function to unregister the hook.
1134
+ * @listens router:afterEach
1135
+ */
1136
+ onAfterEach(hook: NavigationHook): () => void;
1137
+ /**
1138
+ * Registers a global error handler for navigation errors.
1139
+ * @param {(error: Error, to?: RouteLocation, from?: RouteLocation) => void} handler - The error handler function.
1140
+ * @returns {() => void} A function to unregister the handler.
1141
+ * @listens router:error
1142
+ */
1143
+ onError(handler: (error: Error, to?: RouteLocation, from?: RouteLocation) => void): () => void;
1144
+ /**
1145
+ * Registers a plugin with the router.
1146
+ * Logs a warning if the plugin is already registered.
1147
+ *
1148
+ * @param {RouterPlugin} plugin - The plugin to register (must have install method).
1149
+ * @param {Record<string, unknown>} [options={}] - Options to pass to plugin.install().
1150
+ * @returns {void}
1151
+ * @throws {Error} If plugin does not have an install method.
1152
+ */
1153
+ use(plugin: RouterPlugin, options?: Record<string, unknown>): void;
1154
+ /**
1155
+ * Gets all registered plugins.
1156
+ * @returns {RouterPlugin[]} Array of registered plugins.
1157
+ */
1158
+ getPlugins(): RouterPlugin[];
1159
+ /**
1160
+ * Gets a plugin by name.
1161
+ * @param {string} name - The plugin name.
1162
+ * @returns {RouterPlugin | undefined} The plugin or undefined.
1163
+ */
1164
+ getPlugin(name: string): RouterPlugin | undefined;
1165
+ /**
1166
+ * Removes a plugin from the router.
1167
+ * @param {string} name - The plugin name.
1168
+ * @returns {boolean} True if the plugin was removed.
1169
+ */
1170
+ removePlugin(name: string): boolean;
1171
+ /**
1172
+ * Sets a custom error handler. Used by error handling plugins.
1173
+ * Logs a warning if the provided handler is invalid (missing required methods).
1174
+ * @param {RouterErrorHandler} errorHandler - The error handler object with handle, warn, and log methods.
1175
+ * @returns {void}
1176
+ */
1177
+ setErrorHandler(errorHandler: RouterErrorHandler): void;
1178
+ }
1179
+
1180
+ declare namespace StorePlugin {
1181
+ let name: string;
1182
+ let version: string;
1183
+ let description: string;
1184
+ /**
1185
+ * Installs the plugin into the Eleva instance.
1186
+ *
1187
+ * @public
1188
+ * @param {Eleva} eleva - The Eleva instance.
1189
+ * @param {StoreOptions} options - Plugin configuration options.
1190
+ * @param {Record<string, unknown>} [options.state={}] - Initial state object.
1191
+ * @param {Record<string, ActionFunction>} [options.actions={}] - Action functions for state mutations.
1192
+ * @param {Record<string, StoreModule>} [options.namespaces={}] - Namespaced modules for organizing store.
1193
+ * @param {StorePersistenceOptions} [options.persistence] - Persistence configuration.
1194
+ * @param {boolean} [options.persistence.enabled=false] - Enable state persistence.
1195
+ * @param {string} [options.persistence.key="eleva-store"] - Storage key.
1196
+ * @param {'localStorage' | 'sessionStorage'} [options.persistence.storage="localStorage"] - Storage type.
1197
+ * @param {string[]} [options.persistence.include] - Dot-path prefixes to persist (e.g., "auth.user")
1198
+ * @param {string[]} [options.persistence.exclude] - Dot-path prefixes to exclude (applies when include is empty).
1199
+ * @param {boolean} [options.devTools=false] - Enable development tools integration.
1200
+ * @param {(error: Error, context: string) => void} [options.onError=null] - Error handler function.
1201
+ * @returns {void}
1202
+ * @description
1203
+ * Installs the store and injects `store` into component setup context by wrapping
1204
+ * `eleva.mount` and `eleva._mountComponents`. Also exposes `eleva.store` and
1205
+ * helper methods (`eleva.dispatch`, `eleva.getState`, `eleva.subscribe`, `eleva.createAction`).
1206
+ * Uninstall restores the originals.
1207
+ *
1208
+ * @example
1209
+ * // Basic installation
1210
+ * app.use(StorePlugin, {
1211
+ * state: { count: 0, user: null },
1212
+ * actions: {
1213
+ * increment: (state) => state.count.value++,
1214
+ * setUser: (state, user) => state.user.value = user
1215
+ * }
1216
+ * });
1217
+ *
1218
+ * // Advanced installation with persistence and namespaces
1219
+ * app.use(StorePlugin, {
1220
+ * state: { theme: "light" },
1221
+ * namespaces: {
1222
+ * auth: {
1223
+ * state: { user: null, token: null },
1224
+ * actions: {
1225
+ * login: (state, { user, token }) => {
1226
+ * state.auth.user.value = user;
1227
+ * state.auth.token.value = token;
1228
+ * },
1229
+ * logout: (state) => {
1230
+ * state.auth.user.value = null;
1231
+ * state.auth.token.value = null;
1232
+ * }
1233
+ * }
1234
+ * }
1235
+ * },
1236
+ * persistence: {
1237
+ * enabled: true,
1238
+ * include: ["theme", "auth.user"]
1239
+ * }
1240
+ * });
1241
+ */
1242
+ function install(eleva: Eleva, options?: StoreOptions): void;
1243
+ /**
1244
+ * Uninstalls the plugin from the Eleva instance.
1245
+ *
1246
+ * @public
1247
+ * @param {Eleva} eleva - The Eleva instance.
1248
+ * @returns {void}
1249
+ * @description
1250
+ * Restores the original Eleva methods and removes all plugin-specific
1251
+ * functionality. This method should be called when the plugin is no
1252
+ * longer needed.
1253
+ * Also removes `eleva.store` and top-level helpers (`eleva.dispatch`,
1254
+ * `eleva.getState`, `eleva.subscribe`, `eleva.createAction`).
1255
+ *
1256
+ * @example
1257
+ * // Uninstall the plugin
1258
+ * StorePlugin.uninstall(app);
1259
+ */
1260
+ function uninstall(eleva: Eleva): void;
1261
+ }
1262
+
1263
+ /**
1264
+ * Type imports from the Eleva core library.
1265
+ */
1266
+ type Eleva = eleva.Eleva;
1267
+ /**
1268
+ * Generic type import.
1269
+ */
1270
+ type Signal<T> = eleva.Signal<T>;
1271
+ /**
1272
+ * Store configuration options.
1273
+ */
1274
+ type StoreOptions = {
1275
+ /**
1276
+ * Initial state object.
1277
+ */
1278
+ state?: Record<string, unknown> | undefined;
1279
+ /**
1280
+ * Action functions for state mutations.
1281
+ */
1282
+ actions?: Record<string, ActionFunction> | undefined;
1283
+ /**
1284
+ * Namespaced modules for organizing store.
1285
+ */
1286
+ namespaces?: Record<string, StoreModule> | undefined;
1287
+ /**
1288
+ * Persistence configuration.
1289
+ */
1290
+ persistence?: StorePersistenceOptions | undefined;
1291
+ /**
1292
+ * Enable development tools integration.
1293
+ */
1294
+ devTools?: boolean | undefined;
1295
+ /**
1296
+ * Error handler function.
1297
+ */
1298
+ onError?: StoreErrorHandler | undefined;
1299
+ };
1300
+ /**
1301
+ * Namespaced store module definition.
1302
+ */
1303
+ type StoreModule = {
1304
+ /**
1305
+ * Module state.
1306
+ */
1307
+ state: Record<string, unknown>;
1308
+ /**
1309
+ * Module actions.
1310
+ */
1311
+ actions?: Record<string, ActionFunction> | undefined;
1312
+ };
1313
+ /**
1314
+ * Store persistence configuration.
1315
+ */
1316
+ type StorePersistenceOptions = {
1317
+ /**
1318
+ * Enable state persistence.
1319
+ */
1320
+ enabled?: boolean | undefined;
1321
+ /**
1322
+ * Storage key (default: "eleva-store").
1323
+ */
1324
+ key?: string | undefined;
1325
+ /**
1326
+ * Storage type.
1327
+ */
1328
+ storage?: "localStorage" | "sessionStorage" | undefined;
1329
+ /**
1330
+ * Dot-path prefixes to persist (e.g., "auth.user").
1331
+ */
1332
+ include?: string[] | undefined;
1333
+ /**
1334
+ * Dot-path prefixes to exclude.
1335
+ */
1336
+ exclude?: string[] | undefined;
1337
+ };
1338
+ /**
1339
+ * Store error handler callback.
1340
+ */
1341
+ type StoreErrorHandler = (error: Error, context: string) => void;
1342
+ /**
1343
+ * Reactive state tree containing signals and nested namespaces.
1344
+ */
1345
+ type StoreState = Record<string, Signal<unknown> | Record<string, unknown>>;
1346
+ /**
1347
+ * Action function signature for store actions.
1348
+ */
1349
+ type ActionFunction = (state: StoreState, payload?: unknown) => unknown;
1350
+
1351
+ export { AttrPlugin as Attr, RouterPlugin as Router, StorePlugin as Store };
1352
+ //# sourceMappingURL=eleva-plugins.d.ts.map