kimu-core 0.4.1

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 (146) hide show
  1. package/.editorconfig +30 -0
  2. package/.gitattributes +11 -0
  3. package/.github/FUNDING.yml +8 -0
  4. package/.github/copilot-instructions.md +103 -0
  5. package/.github/kimu-copilot-instructions.md +3779 -0
  6. package/.github/workflows/deploy-demo.yml +39 -0
  7. package/AUTHORS.md +20 -0
  8. package/CHANGELOG.md +20 -0
  9. package/CODE_GUIDELINES.md +165 -0
  10. package/CODE_OF_CONDUCT.md +47 -0
  11. package/CONTRIBUTING.md +62 -0
  12. package/FUNDING.md +31 -0
  13. package/ISSUE_GUIDELINES.md +74 -0
  14. package/LICENSE +17 -0
  15. package/LICENSE.it.md +17 -0
  16. package/MPL-2.0.txt +373 -0
  17. package/NOTICE +65 -0
  18. package/README-KIMU.md +40 -0
  19. package/README.it.md +208 -0
  20. package/README.md +266 -0
  21. package/SECURITY.md +64 -0
  22. package/docs/get-started-en.md +207 -0
  23. package/docs/images/icon.svg +64 -0
  24. package/docs/images/logo_kimu.png +0 -0
  25. package/docs/index.md +29 -0
  26. package/env/dev.config.json +6 -0
  27. package/env/local.config.json +6 -0
  28. package/env/prod.config.json +6 -0
  29. package/env/staging.config.json +6 -0
  30. package/env/test.config.json +4 -0
  31. package/icon.svg +10 -0
  32. package/logo_kimu.png +0 -0
  33. package/package.json +79 -0
  34. package/public/favicon.svg +64 -0
  35. package/public/logo_kimu.svg +1 -0
  36. package/scripts/build-all-config.js +59 -0
  37. package/scripts/build-all-core.js +65 -0
  38. package/scripts/build-all-extensions.js +64 -0
  39. package/scripts/build-all-modules.js +99 -0
  40. package/scripts/build-extension.js +60 -0
  41. package/scripts/clear-kimu-build.js +31 -0
  42. package/scripts/generate-kimu-build-config.js +79 -0
  43. package/scripts/install-module.js +162 -0
  44. package/scripts/list-modules.js +109 -0
  45. package/scripts/minify-css-assets.js +82 -0
  46. package/scripts/remove-module.js +122 -0
  47. package/scripts/utils/fix-imports.js +85 -0
  48. package/src/assets/index.css +43 -0
  49. package/src/assets/kimu-style.css +84 -0
  50. package/src/assets/style.css +116 -0
  51. package/src/config/kimu-base-config.json +5 -0
  52. package/src/core/index.ts +47 -0
  53. package/src/core/kimu-app.ts +76 -0
  54. package/src/core/kimu-asset-manager.ts +167 -0
  55. package/src/core/kimu-component-element.ts +325 -0
  56. package/src/core/kimu-component.ts +33 -0
  57. package/src/core/kimu-engine.ts +188 -0
  58. package/src/core/kimu-extension-manager.ts +281 -0
  59. package/src/core/kimu-global-styles.ts +136 -0
  60. package/src/core/kimu-module-manager.ts +69 -0
  61. package/src/core/kimu-module.ts +21 -0
  62. package/src/core/kimu-path-config.ts +127 -0
  63. package/src/core/kimu-reactive.ts +196 -0
  64. package/src/core/kimu-render.ts +91 -0
  65. package/src/core/kimu-store.ts +147 -0
  66. package/src/core/kimu-types.ts +65 -0
  67. package/src/extensions/.gitkeep +0 -0
  68. package/src/extensions/extensions-manifest.json +13 -0
  69. package/src/extensions/kimu-home/component.ts +80 -0
  70. package/src/extensions/kimu-home/lang/en.json +5 -0
  71. package/src/extensions/kimu-home/lang/it.json +5 -0
  72. package/src/extensions/kimu-home/style.css +61 -0
  73. package/src/extensions/kimu-home/view.html +51 -0
  74. package/src/index.html +26 -0
  75. package/src/main.ts +68 -0
  76. package/src/modules/.gitkeep +0 -0
  77. package/src/modules/README.md +79 -0
  78. package/src/modules/i18n/README.it.md +63 -0
  79. package/src/modules/i18n/README.md +63 -0
  80. package/src/modules/i18n/kimu-global-lang.ts +26 -0
  81. package/src/modules/i18n/kimu-i18n-service.ts +108 -0
  82. package/src/modules/i18n/manifest.json +22 -0
  83. package/src/modules/i18n/module.ts +39 -0
  84. package/src/modules/modules-manifest.json +12 -0
  85. package/src/modules-repository/README.md +108 -0
  86. package/src/modules-repository/api-axios/CHANGELOG.md +48 -0
  87. package/src/modules-repository/api-axios/QUICK-REFERENCE.md +178 -0
  88. package/src/modules-repository/api-axios/README.md +304 -0
  89. package/src/modules-repository/api-axios/api-axios-service.ts +355 -0
  90. package/src/modules-repository/api-axios/examples.ts +293 -0
  91. package/src/modules-repository/api-axios/index.ts +19 -0
  92. package/src/modules-repository/api-axios/interfaces.ts +71 -0
  93. package/src/modules-repository/api-axios/module.ts +41 -0
  94. package/src/modules-repository/api-core/CHANGELOG.md +42 -0
  95. package/src/modules-repository/api-core/QUICK-REFERENCE.md +192 -0
  96. package/src/modules-repository/api-core/README.md +435 -0
  97. package/src/modules-repository/api-core/api-core-service.ts +289 -0
  98. package/src/modules-repository/api-core/examples.ts +432 -0
  99. package/src/modules-repository/api-core/index.ts +8 -0
  100. package/src/modules-repository/api-core/interfaces.ts +83 -0
  101. package/src/modules-repository/api-core/module.ts +30 -0
  102. package/src/modules-repository/event-bus/README.md +273 -0
  103. package/src/modules-repository/event-bus/event-bus-service.ts +176 -0
  104. package/src/modules-repository/event-bus/module.ts +30 -0
  105. package/src/modules-repository/i18n/README.it.md +63 -0
  106. package/src/modules-repository/i18n/README.md +63 -0
  107. package/src/modules-repository/i18n/kimu-global-lang.ts +26 -0
  108. package/src/modules-repository/i18n/kimu-i18n-service.ts +108 -0
  109. package/src/modules-repository/i18n/manifest.json +22 -0
  110. package/src/modules-repository/i18n/module.ts +39 -0
  111. package/src/modules-repository/notification/README.md +423 -0
  112. package/src/modules-repository/notification/module.ts +30 -0
  113. package/src/modules-repository/notification/notification-service.ts +436 -0
  114. package/src/modules-repository/router/README.it.md +39 -0
  115. package/src/modules-repository/router/README.md +39 -0
  116. package/src/modules-repository/router/manifest.json +21 -0
  117. package/src/modules-repository/router/module.ts +23 -0
  118. package/src/modules-repository/router/router.ts +144 -0
  119. package/src/modules-repository/state/README.md +409 -0
  120. package/src/modules-repository/state/module.ts +30 -0
  121. package/src/modules-repository/state/state-service.ts +296 -0
  122. package/src/modules-repository/theme/README.md +267 -0
  123. package/src/modules-repository/theme/module.ts +30 -0
  124. package/src/modules-repository/theme/pre-build.js +40 -0
  125. package/src/modules-repository/theme/theme-service.ts +389 -0
  126. package/src/modules-repository/theme/themes/theme-cherry-blossom.css +78 -0
  127. package/src/modules-repository/theme/themes/theme-cozy.css +111 -0
  128. package/src/modules-repository/theme/themes/theme-cyberpunk.css +150 -0
  129. package/src/modules-repository/theme/themes/theme-dark.css +79 -0
  130. package/src/modules-repository/theme/themes/theme-forest.css +171 -0
  131. package/src/modules-repository/theme/themes/theme-gold.css +100 -0
  132. package/src/modules-repository/theme/themes/theme-high-contrast.css +126 -0
  133. package/src/modules-repository/theme/themes/theme-lava.css +101 -0
  134. package/src/modules-repository/theme/themes/theme-lavender.css +90 -0
  135. package/src/modules-repository/theme/themes/theme-light.css +79 -0
  136. package/src/modules-repository/theme/themes/theme-matrix.css +103 -0
  137. package/src/modules-repository/theme/themes/theme-midnight.css +81 -0
  138. package/src/modules-repository/theme/themes/theme-nord.css +94 -0
  139. package/src/modules-repository/theme/themes/theme-ocean.css +84 -0
  140. package/src/modules-repository/theme/themes/theme-retro80s.css +343 -0
  141. package/src/modules-repository/theme/themes/theme-sunset.css +62 -0
  142. package/src/modules-repository/theme/themes-config.d.ts +27 -0
  143. package/src/modules-repository/theme/themes-config.json +213 -0
  144. package/src/vite-env.d.ts +1 -0
  145. package/tsconfig.json +33 -0
  146. package/vite.config.ts +99 -0
@@ -0,0 +1,436 @@
1
+ /**
2
+ * Notification Service for KIMU-Core
3
+ *
4
+ * Provides toast notifications, alerts, and user feedback system.
5
+ * Supports different notification types, durations, and positions.
6
+ *
7
+ * @module NotificationService
8
+ * @version 1.0.0
9
+ */
10
+
11
+ export type NotificationType = 'success' | 'error' | 'warning' | 'info';
12
+ export type NotificationPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'top-center' | 'bottom-center';
13
+
14
+ export interface NotificationOptions {
15
+ type?: NotificationType;
16
+ duration?: number; // in milliseconds, 0 = no auto-dismiss
17
+ position?: NotificationPosition;
18
+ dismissible?: boolean;
19
+ icon?: string;
20
+ onClick?: () => void;
21
+ onClose?: () => void;
22
+ }
23
+
24
+ export interface Notification {
25
+ id: string;
26
+ message: string;
27
+ type: NotificationType;
28
+ duration: number;
29
+ position: NotificationPosition;
30
+ dismissible: boolean;
31
+ icon?: string;
32
+ timestamp: number;
33
+ element?: HTMLElement;
34
+ timeoutId?: number;
35
+ onClick?: () => void;
36
+ onClose?: () => void;
37
+ }
38
+
39
+ /**
40
+ * NotificationService - Toast notifications and alerts
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * import { notificationService } from './modules/notification/notification-service';
45
+ *
46
+ * // Show success notification
47
+ * notificationService.success('Operation completed!');
48
+ *
49
+ * // Show error with custom duration
50
+ * notificationService.error('Something went wrong!', { duration: 5000 });
51
+ *
52
+ * // Show info with custom position
53
+ * notificationService.info('New message received', { position: 'bottom-right' });
54
+ * ```
55
+ */
56
+ export class NotificationService {
57
+ private notifications: Map<string, Notification> = new Map();
58
+ private container?: HTMLElement;
59
+ private defaultDuration: number = 3000;
60
+ private defaultPosition: NotificationPosition = 'top-right';
61
+ private maxNotifications: number = 5;
62
+ private debugMode: boolean = false;
63
+
64
+ constructor() {
65
+ this.initContainer();
66
+ }
67
+
68
+ /**
69
+ * Enable or disable debug mode
70
+ */
71
+ setDebugMode(enabled: boolean): void {
72
+ this.debugMode = enabled;
73
+ }
74
+
75
+ /**
76
+ * Set default notification duration
77
+ */
78
+ setDefaultDuration(duration: number): void {
79
+ this.defaultDuration = duration;
80
+ }
81
+
82
+ /**
83
+ * Set default notification position
84
+ */
85
+ setDefaultPosition(position: NotificationPosition): void {
86
+ this.defaultPosition = position;
87
+ }
88
+
89
+ /**
90
+ * Set maximum number of visible notifications
91
+ */
92
+ setMaxNotifications(max: number): void {
93
+ this.maxNotifications = max;
94
+ }
95
+
96
+ /**
97
+ * Show a success notification
98
+ */
99
+ success(message: string, options?: NotificationOptions): string {
100
+ return this.show(message, { ...options, type: 'success' });
101
+ }
102
+
103
+ /**
104
+ * Show an error notification
105
+ */
106
+ error(message: string, options?: NotificationOptions): string {
107
+ return this.show(message, { ...options, type: 'error' });
108
+ }
109
+
110
+ /**
111
+ * Show a warning notification
112
+ */
113
+ warning(message: string, options?: NotificationOptions): string {
114
+ return this.show(message, { ...options, type: 'warning' });
115
+ }
116
+
117
+ /**
118
+ * Show an info notification
119
+ */
120
+ info(message: string, options?: NotificationOptions): string {
121
+ return this.show(message, { ...options, type: 'info' });
122
+ }
123
+
124
+ /**
125
+ * Show a notification with custom options
126
+ */
127
+ show(message: string, options: NotificationOptions = {}): string {
128
+ const id = this.generateId();
129
+
130
+ const notification: Notification = {
131
+ id,
132
+ message,
133
+ type: options.type || 'info',
134
+ duration: options.duration !== undefined ? options.duration : this.defaultDuration,
135
+ position: options.position || this.defaultPosition,
136
+ dismissible: options.dismissible !== undefined ? options.dismissible : true,
137
+ icon: options.icon || this.getDefaultIcon(options.type || 'info'),
138
+ timestamp: Date.now(),
139
+ onClick: options.onClick,
140
+ onClose: options.onClose
141
+ };
142
+
143
+ if (this.debugMode) {
144
+ console.log('[Notification] Show:', notification);
145
+ }
146
+
147
+ // Remove oldest notification if max limit reached
148
+ if (this.notifications.size >= this.maxNotifications) {
149
+ const oldestId = Array.from(this.notifications.keys())[0];
150
+ this.dismiss(oldestId);
151
+ }
152
+
153
+ this.notifications.set(id, notification);
154
+ this.renderNotification(notification);
155
+
156
+ // Auto-dismiss if duration > 0
157
+ if (notification.duration > 0) {
158
+ notification.timeoutId = window.setTimeout(() => {
159
+ this.dismiss(id);
160
+ }, notification.duration);
161
+ }
162
+
163
+ return id;
164
+ }
165
+
166
+ /**
167
+ * Dismiss a specific notification
168
+ */
169
+ dismiss(id: string): void {
170
+ const notification = this.notifications.get(id);
171
+ if (!notification) return;
172
+
173
+ if (this.debugMode) {
174
+ console.log('[Notification] Dismiss:', id);
175
+ }
176
+
177
+ // Clear timeout
178
+ if (notification.timeoutId) {
179
+ clearTimeout(notification.timeoutId);
180
+ }
181
+
182
+ // Remove element with animation
183
+ if (notification.element) {
184
+ notification.element.classList.add('kimu-notification-exit');
185
+ setTimeout(() => {
186
+ notification.element?.remove();
187
+ }, 300);
188
+ }
189
+
190
+ // Call onClose callback
191
+ if (notification.onClose) {
192
+ notification.onClose();
193
+ }
194
+
195
+ this.notifications.delete(id);
196
+ }
197
+
198
+ /**
199
+ * Dismiss all notifications
200
+ */
201
+ dismissAll(): void {
202
+ const ids = Array.from(this.notifications.keys());
203
+ ids.forEach(id => this.dismiss(id));
204
+ }
205
+
206
+ /**
207
+ * Get all active notifications
208
+ */
209
+ getAll(): Notification[] {
210
+ return Array.from(this.notifications.values());
211
+ }
212
+
213
+ /**
214
+ * Get notification count
215
+ */
216
+ getCount(): number {
217
+ return this.notifications.size;
218
+ }
219
+
220
+ // Private methods
221
+
222
+ private initContainer(): void {
223
+ if (typeof document === 'undefined') return;
224
+
225
+ this.container = document.createElement('div');
226
+ this.container.id = 'kimu-notification-container';
227
+ this.injectStyles();
228
+ document.body.appendChild(this.container);
229
+ }
230
+
231
+ private renderNotification(notification: Notification): void {
232
+ if (!this.container) return;
233
+
234
+ const element = document.createElement('div');
235
+ element.className = `kimu-notification kimu-notification-${notification.type} kimu-notification-${notification.position}`;
236
+ element.setAttribute('data-id', notification.id);
237
+
238
+ const content = `
239
+ <div class="kimu-notification-content">
240
+ ${notification.icon ? `<span class="kimu-notification-icon">${notification.icon}</span>` : ''}
241
+ <span class="kimu-notification-message">${this.escapeHtml(notification.message)}</span>
242
+ </div>
243
+ ${notification.dismissible ? '<button class="kimu-notification-close" aria-label="Close">×</button>' : ''}
244
+ `;
245
+
246
+ element.innerHTML = content;
247
+
248
+ // Add click handlers
249
+ if (notification.onClick) {
250
+ element.addEventListener('click', (e) => {
251
+ if (!(e.target as HTMLElement).classList.contains('kimu-notification-close')) {
252
+ notification.onClick!();
253
+ }
254
+ });
255
+ }
256
+
257
+ if (notification.dismissible) {
258
+ const closeBtn = element.querySelector('.kimu-notification-close');
259
+ closeBtn?.addEventListener('click', (e) => {
260
+ e.stopPropagation();
261
+ this.dismiss(notification.id);
262
+ });
263
+ }
264
+
265
+ notification.element = element;
266
+ this.container.appendChild(element);
267
+
268
+ // Trigger animation
269
+ setTimeout(() => element.classList.add('kimu-notification-enter'), 10);
270
+ }
271
+
272
+ private generateId(): string {
273
+ return `notification-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
274
+ }
275
+
276
+ private getDefaultIcon(type: NotificationType): string {
277
+ const icons = {
278
+ success: '✅',
279
+ error: '❌',
280
+ warning: '⚠️',
281
+ info: 'ℹ️'
282
+ };
283
+ return icons[type];
284
+ }
285
+
286
+ private escapeHtml(text: string): string {
287
+ const div = document.createElement('div');
288
+ div.textContent = text;
289
+ return div.innerHTML;
290
+ }
291
+
292
+ private injectStyles(): void {
293
+ if (typeof document === 'undefined') return;
294
+ if (document.getElementById('kimu-notification-styles')) return;
295
+
296
+ const style = document.createElement('style');
297
+ style.id = 'kimu-notification-styles';
298
+ style.textContent = `
299
+ #kimu-notification-container {
300
+ position: fixed;
301
+ z-index: 9999;
302
+ pointer-events: none;
303
+ }
304
+
305
+ .kimu-notification {
306
+ position: fixed;
307
+ min-width: 280px;
308
+ max-width: 400px;
309
+ padding: 16px 20px;
310
+ margin: 12px;
311
+ background: white;
312
+ border-radius: 8px;
313
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
314
+ display: flex;
315
+ align-items: center;
316
+ justify-content: space-between;
317
+ opacity: 0;
318
+ transform: translateY(-20px);
319
+ transition: all 0.3s ease;
320
+ pointer-events: auto;
321
+ cursor: default;
322
+ }
323
+
324
+ .kimu-notification-enter {
325
+ opacity: 1;
326
+ transform: translateY(0);
327
+ }
328
+
329
+ .kimu-notification-exit {
330
+ opacity: 0;
331
+ transform: translateY(-20px);
332
+ }
333
+
334
+ .kimu-notification-content {
335
+ display: flex;
336
+ align-items: center;
337
+ gap: 12px;
338
+ flex: 1;
339
+ }
340
+
341
+ .kimu-notification-icon {
342
+ font-size: 20px;
343
+ line-height: 1;
344
+ }
345
+
346
+ .kimu-notification-message {
347
+ color: #333;
348
+ font-size: 14px;
349
+ line-height: 1.5;
350
+ }
351
+
352
+ .kimu-notification-close {
353
+ background: none;
354
+ border: none;
355
+ font-size: 24px;
356
+ line-height: 1;
357
+ color: #999;
358
+ cursor: pointer;
359
+ padding: 0;
360
+ margin-left: 12px;
361
+ transition: color 0.2s;
362
+ }
363
+
364
+ .kimu-notification-close:hover {
365
+ color: #333;
366
+ }
367
+
368
+ /* Types */
369
+ .kimu-notification-success {
370
+ background: #f0fdf4;
371
+ border-left: 4px solid #22c55e;
372
+ }
373
+
374
+ .kimu-notification-error {
375
+ background: #fef2f2;
376
+ border-left: 4px solid #ef4444;
377
+ }
378
+
379
+ .kimu-notification-warning {
380
+ background: #fffbeb;
381
+ border-left: 4px solid #f59e0b;
382
+ }
383
+
384
+ .kimu-notification-info {
385
+ background: #eff6ff;
386
+ border-left: 4px solid #3b82f6;
387
+ }
388
+
389
+ /* Positions */
390
+ .kimu-notification-top-right {
391
+ top: 0;
392
+ right: 0;
393
+ }
394
+
395
+ .kimu-notification-top-left {
396
+ top: 0;
397
+ left: 0;
398
+ }
399
+
400
+ .kimu-notification-bottom-right {
401
+ bottom: 0;
402
+ right: 0;
403
+ }
404
+
405
+ .kimu-notification-bottom-left {
406
+ bottom: 0;
407
+ left: 0;
408
+ }
409
+
410
+ .kimu-notification-top-center {
411
+ top: 0;
412
+ left: 50%;
413
+ transform: translateX(-50%) translateY(-20px);
414
+ }
415
+
416
+ .kimu-notification-top-center.kimu-notification-enter {
417
+ transform: translateX(-50%) translateY(0);
418
+ }
419
+
420
+ .kimu-notification-bottom-center {
421
+ bottom: 0;
422
+ left: 50%;
423
+ transform: translateX(-50%) translateY(20px);
424
+ }
425
+
426
+ .kimu-notification-bottom-center.kimu-notification-enter {
427
+ transform: translateX(-50%) translateY(0);
428
+ }
429
+ `;
430
+
431
+ document.head.appendChild(style);
432
+ }
433
+ }
434
+
435
+ // Export singleton instance
436
+ export const notificationService = new NotificationService();
@@ -0,0 +1,39 @@
1
+ # Kimu Router Module
2
+
3
+ Questo modulo fornisce un servizio di routing per kimu-core, permettendo la gestione delle rotte e la navigazione tra componenti/estensioni in base all'URL.
4
+
5
+ ## Funzionalità
6
+ - Configurazione centralizzata delle rotte
7
+ - Navigazione tramite history API
8
+ - Callback sugli eventi di cambio rotta
9
+ - API per registrare nuove rotte dinamicamente
10
+
11
+ ## Utilizzo
12
+
13
+ ```typescript
14
+ import { KimuRouterService } from './src/modules/router/router';
15
+
16
+ const router = KimuRouterService.getInstance();
17
+ router.configure([
18
+ { path: '/', component: HomeComponent },
19
+ { path: '/about', component: AboutComponent },
20
+ ]);
21
+
22
+ router.onRouteChange((route) => {
23
+ // Logica per gestire il cambio rotta
24
+ });
25
+
26
+ // Per navigare
27
+ router.navigate('/about');
28
+ ```
29
+
30
+ ## Estensione
31
+ - Puoi estendere il sistema per supportare parametri dinamici, fallback, rotte nidificate, ecc.
32
+ - Le estensioni possono registrare le proprie rotte tramite `registerRoute`.
33
+
34
+ ## Best practice
35
+ - Mantieni la configurazione delle rotte separata dalla logica di rendering.
36
+ - Documenta sempre le rotte principali e i parametri accettati.
37
+
38
+ ---
39
+ Autore: UnicoVerso
@@ -0,0 +1,39 @@
1
+ # Kimu Router Module
2
+
3
+ This module provides a routing service for kimu-core, allowing you to manage routes and navigation between components/extensions based on the URL.
4
+
5
+ ## Features
6
+ - Centralized route configuration
7
+ - Navigation via the History API
8
+ - Callback on route change events
9
+ - API to register new routes dynamically
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { KimuRouterService } from './src/modules/router/router';
15
+
16
+ const router = KimuRouterService.getInstance();
17
+ router.configure([
18
+ { path: '/', component: HomeComponent },
19
+ { path: '/about', component: AboutComponent },
20
+ ]);
21
+
22
+ router.onRouteChange((route) => {
23
+ // Logic to handle route change
24
+ });
25
+
26
+ // To navigate
27
+ router.navigate('/about');
28
+ ```
29
+
30
+ ## Extension
31
+ - You can extend the system to support dynamic parameters, fallback, nested routes, etc.
32
+ - Extensions can register their own routes via `registerRoute`.
33
+
34
+ ## Best practices
35
+ - Keep route configuration separated from rendering logic.
36
+ - Always document main routes and accepted parameters.
37
+
38
+ ---
39
+ Author: UnicoVerso
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "router",
3
+ "version": "1.0.0",
4
+ "description": "Client-side routing module for KIMU applications with History API support",
5
+ "author": "KIMU Team",
6
+ "license": "MPL-2.0",
7
+ "dependencies": [],
8
+ "kimuCoreVersion": "^0.3.0",
9
+ "keywords": [
10
+ "router",
11
+ "routing",
12
+ "navigation",
13
+ "history-api",
14
+ "spa"
15
+ ],
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/UnicoVerso/kimu-core",
19
+ "directory": "src/modules/router"
20
+ }
21
+ }
@@ -0,0 +1,23 @@
1
+ // KimuRouterModule
2
+ // Provides the routing service as a KimuModule
3
+ // Inspired by the structure of the i18n module
4
+
5
+ import { KimuModule } from '../../core/kimu-module';
6
+ import { KimuRouterService } from './router';
7
+ import { KimuRouterModuleOptions } from './router';
8
+
9
+ export default class KimuRouterModule extends KimuModule {
10
+ private service: KimuRouterService;
11
+
12
+ constructor(name: string = 'router', version: string = '1.0.0', options?: KimuRouterModuleOptions) {
13
+ super(name, version, options);
14
+ this.service = KimuRouterService.getInstance();
15
+ if (options?.routes) {
16
+ this.service.configure(options.routes);
17
+ }
18
+ }
19
+
20
+ getService(): KimuRouterService {
21
+ return this.service;
22
+ }
23
+ }
@@ -0,0 +1,144 @@
1
+ // Kimu Router Module
2
+ // Provides routing service and configuration for kimu-core extensions and core
3
+ // Author: UnicoVerso
4
+ //
5
+ // Usage: Import KimuRouterService and configure routes in your app or extension.
6
+
7
+ // Router module options (extensible for future features)
8
+ import { KimuModuleOptions } from '../../core/kimu-types';
9
+
10
+ /**
11
+ * RouteConfig defines a single route mapping for the router.
12
+ * - path: URL path to match
13
+ * - component: KimuComponentElement to render
14
+ * - name: Optional route name
15
+ * - meta: Optional metadata for custom usage
16
+ */
17
+ export interface RouteConfig {
18
+ path: string;
19
+ component: any; // Should extend KimuComponentElement
20
+ name?: string;
21
+ meta?: Record<string, any>;
22
+ }
23
+
24
+ /**
25
+ * Options for initializing the router module.
26
+ * - routes: Array of RouteConfig for initial setup
27
+ */
28
+ export interface KimuRouterModuleOptions extends KimuModuleOptions {
29
+ routes?: RouteConfig[];
30
+ }
31
+
32
+ /**
33
+ * Callback type for route change events.
34
+ * - route: The matched RouteConfig
35
+ * - params: Optional route parameters (future extension)
36
+ */
37
+ export type RouteChangeCallback = (route: RouteConfig, params?: Record<string, string>) => void;
38
+
39
+ /**
40
+ * KimuRouterService provides SPA-like routing for KIMU extensions/components.
41
+ * Use getInstance() for singleton access.
42
+ */
43
+ export class KimuRouterService {
44
+ /** Singleton instance */
45
+ private static instance: KimuRouterService;
46
+ /** Registered routes */
47
+ private routes: RouteConfig[] = [];
48
+ /** Currently active route */
49
+ private currentRoute: RouteConfig | null = null;
50
+ /** Listeners for route change events */
51
+ private listeners: RouteChangeCallback[] = [];
52
+
53
+ /**
54
+ * Private constructor. Sets up popstate listener for browser navigation.
55
+ */
56
+ private constructor() {
57
+ window.addEventListener('popstate', this.handlePopState.bind(this));
58
+ }
59
+
60
+ /**
61
+ * Returns the singleton instance of the router service.
62
+ */
63
+ public static getInstance(): KimuRouterService {
64
+ if (!KimuRouterService.instance) {
65
+ KimuRouterService.instance = new KimuRouterService();
66
+ }
67
+ return KimuRouterService.instance;
68
+ }
69
+
70
+ /**
71
+ * Configure the router with a set of routes.
72
+ * @param routes Array of RouteConfig
73
+ */
74
+ public configure(routes: RouteConfig[]): void {
75
+ this.routes = routes;
76
+ }
77
+
78
+ /**
79
+ * Register a new route at runtime.
80
+ * @param route RouteConfig to add
81
+ */
82
+ public registerRoute(route: RouteConfig): void {
83
+ this.routes.push(route);
84
+ }
85
+
86
+ /**
87
+ * Navigate to a given path, updating browser history and resolving route.
88
+ * @param path URL path to navigate to
89
+ */
90
+ public navigate(path: string): void {
91
+ history.pushState({}, '', path);
92
+ this.resolveRoute(path);
93
+ }
94
+
95
+ /**
96
+ * Get the currently active route.
97
+ */
98
+ public getCurrentRoute(): RouteConfig | null {
99
+ return this.currentRoute;
100
+ }
101
+
102
+ /**
103
+ * Register a callback for route change events.
104
+ * @param callback Function to call on route change
105
+ */
106
+ public onRouteChange(callback: RouteChangeCallback): void {
107
+ this.listeners.push(callback);
108
+ }
109
+
110
+ /**
111
+ * Handles browser back/forward navigation.
112
+ */
113
+ private handlePopState(): void {
114
+ this.resolveRoute(window.location.pathname);
115
+ }
116
+
117
+ /**
118
+ * Resolves the route for a given path and notifies listeners.
119
+ * @param path URL path to resolve
120
+ */
121
+ private resolveRoute(path: string): void {
122
+ const match = this.routes.find(r => r.path === path);
123
+ this.currentRoute = match || null;
124
+ this.listeners.forEach(cb => cb(this.currentRoute!, this.extractParams(path)));
125
+ }
126
+
127
+ /**
128
+ * Extracts route parameters from the path (future extension).
129
+ * @param _path URL path
130
+ * @returns Object with route params (currently empty)
131
+ */
132
+ private extractParams(_path: string): Record<string, string> {
133
+ // Basic implementation, extend for dynamic params
134
+ return {};
135
+ }
136
+ }
137
+
138
+ // Example usage (in app or extension):
139
+ // const router = KimuRouterService.getInstance();
140
+ // router.configure([
141
+ // { path: '/', component: HomeComponent },
142
+ // { path: '/about', component: AboutComponent },
143
+ // ]);
144
+ // router.onRouteChange((route) => { ... });