@emkodev/emroute 1.6.2 → 1.6.3

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 (128) hide show
  1. package/README.md +6 -6
  2. package/dist/runtime/abstract.runtime.d.ts +94 -0
  3. package/dist/runtime/abstract.runtime.js +339 -0
  4. package/dist/runtime/abstract.runtime.js.map +1 -0
  5. package/dist/runtime/bun/esbuild-runtime-loader.plugin.d.ts +25 -0
  6. package/dist/runtime/bun/esbuild-runtime-loader.plugin.js +72 -0
  7. package/dist/runtime/bun/esbuild-runtime-loader.plugin.js.map +1 -0
  8. package/dist/runtime/bun/fs/bun-fs.runtime.d.ts +21 -0
  9. package/dist/runtime/bun/fs/bun-fs.runtime.js +205 -0
  10. package/dist/runtime/bun/fs/bun-fs.runtime.js.map +1 -0
  11. package/dist/runtime/bun/sqlite/bun-sqlite.runtime.d.ts +27 -0
  12. package/dist/runtime/bun/sqlite/bun-sqlite.runtime.js +234 -0
  13. package/dist/runtime/bun/sqlite/bun-sqlite.runtime.js.map +1 -0
  14. package/dist/runtime/sitemap.generator.d.ts +58 -0
  15. package/dist/runtime/sitemap.generator.js +107 -0
  16. package/dist/runtime/sitemap.generator.js.map +1 -0
  17. package/dist/runtime/universal/fs/universal-fs.runtime.d.ts +29 -0
  18. package/dist/runtime/universal/fs/universal-fs.runtime.js +213 -0
  19. package/dist/runtime/universal/fs/universal-fs.runtime.js.map +1 -0
  20. package/dist/server/codegen.util.d.ts +16 -0
  21. package/dist/server/codegen.util.js +46 -0
  22. package/dist/server/codegen.util.js.map +1 -0
  23. package/dist/server/emroute.server.d.ts +37 -0
  24. package/dist/server/emroute.server.js +314 -0
  25. package/dist/server/emroute.server.js.map +1 -0
  26. package/dist/server/esbuild-manifest.plugin.d.ts +26 -0
  27. package/dist/server/esbuild-manifest.plugin.js +187 -0
  28. package/dist/server/esbuild-manifest.plugin.js.map +1 -0
  29. package/dist/server/scanner.util.d.ts +22 -0
  30. package/dist/server/scanner.util.js +194 -0
  31. package/dist/server/scanner.util.js.map +1 -0
  32. package/dist/server/server-api.type.d.ts +71 -0
  33. package/dist/server/server-api.type.js +9 -0
  34. package/dist/server/server-api.type.js.map +1 -0
  35. package/dist/src/component/abstract.component.d.ts +197 -0
  36. package/dist/src/component/abstract.component.js +84 -0
  37. package/dist/src/component/abstract.component.js.map +1 -0
  38. package/dist/src/component/page.component.d.ts +74 -0
  39. package/dist/src/component/page.component.js +107 -0
  40. package/dist/src/component/page.component.js.map +1 -0
  41. package/dist/src/component/widget.component.d.ts +47 -0
  42. package/dist/src/component/widget.component.js +69 -0
  43. package/dist/src/component/widget.component.js.map +1 -0
  44. package/dist/src/element/component.element.d.ts +79 -0
  45. package/dist/src/element/component.element.js +293 -0
  46. package/dist/src/element/component.element.js.map +1 -0
  47. package/dist/src/element/markdown.element.d.ts +36 -0
  48. package/dist/src/element/markdown.element.js +93 -0
  49. package/dist/src/element/markdown.element.js.map +1 -0
  50. package/dist/src/element/slot.element.d.ts +30 -0
  51. package/dist/src/element/slot.element.js +31 -0
  52. package/dist/src/element/slot.element.js.map +1 -0
  53. package/dist/src/index.d.ts +23 -0
  54. package/dist/src/index.js +24 -0
  55. package/dist/src/index.js.map +1 -0
  56. package/dist/src/overlay/mod.d.ts +9 -0
  57. package/dist/src/overlay/mod.js +9 -0
  58. package/dist/src/overlay/mod.js.map +1 -0
  59. package/dist/src/overlay/overlay.css.d.ts +8 -0
  60. package/dist/src/overlay/overlay.css.js +170 -0
  61. package/dist/src/overlay/overlay.css.js.map +1 -0
  62. package/dist/src/overlay/overlay.service.d.ts +14 -0
  63. package/dist/src/overlay/overlay.service.js +307 -0
  64. package/dist/src/overlay/overlay.service.js.map +1 -0
  65. package/dist/src/overlay/overlay.type.d.ts +33 -0
  66. package/dist/src/overlay/overlay.type.js +11 -0
  67. package/dist/src/overlay/overlay.type.js.map +1 -0
  68. package/dist/src/renderer/spa/base.renderer.d.ts +39 -0
  69. package/dist/src/renderer/spa/base.renderer.js +149 -0
  70. package/dist/src/renderer/spa/base.renderer.js.map +1 -0
  71. package/dist/src/renderer/spa/hash.renderer.d.ts +78 -0
  72. package/dist/src/renderer/spa/hash.renderer.js +162 -0
  73. package/dist/src/renderer/spa/hash.renderer.js.map +1 -0
  74. package/dist/src/renderer/spa/html.renderer.d.ts +81 -0
  75. package/dist/src/renderer/spa/html.renderer.js +304 -0
  76. package/dist/src/renderer/spa/html.renderer.js.map +1 -0
  77. package/dist/src/renderer/spa/mod.d.ts +30 -0
  78. package/dist/src/renderer/spa/mod.js +35 -0
  79. package/dist/src/renderer/spa/mod.js.map +1 -0
  80. package/dist/src/renderer/ssr/html.renderer.d.ts +49 -0
  81. package/dist/src/renderer/ssr/html.renderer.js +108 -0
  82. package/dist/src/renderer/ssr/html.renderer.js.map +1 -0
  83. package/dist/src/renderer/ssr/md.renderer.d.ts +40 -0
  84. package/dist/src/renderer/ssr/md.renderer.js +100 -0
  85. package/dist/src/renderer/ssr/md.renderer.js.map +1 -0
  86. package/dist/src/renderer/ssr/ssr.renderer.d.ts +74 -0
  87. package/dist/src/renderer/ssr/ssr.renderer.js +185 -0
  88. package/dist/src/renderer/ssr/ssr.renderer.js.map +1 -0
  89. package/dist/src/route/route.core.d.ts +129 -0
  90. package/dist/src/route/route.core.js +255 -0
  91. package/dist/src/route/route.core.js.map +1 -0
  92. package/dist/src/route/route.matcher.d.ts +86 -0
  93. package/dist/src/route/route.matcher.js +214 -0
  94. package/dist/src/route/route.matcher.js.map +1 -0
  95. package/dist/src/type/logger.type.d.ts +17 -0
  96. package/dist/src/type/logger.type.js +9 -0
  97. package/dist/src/type/logger.type.js.map +1 -0
  98. package/dist/src/type/markdown.type.d.ts +20 -0
  99. package/dist/src/type/markdown.type.js +2 -0
  100. package/dist/src/type/markdown.type.js.map +1 -0
  101. package/dist/src/type/route.type.d.ts +112 -0
  102. package/dist/src/type/route.type.js +8 -0
  103. package/dist/src/type/route.type.js.map +1 -0
  104. package/dist/src/type/widget.type.d.ts +55 -0
  105. package/dist/src/type/widget.type.js +10 -0
  106. package/dist/src/type/widget.type.js.map +1 -0
  107. package/dist/src/util/html.util.d.ts +29 -0
  108. package/dist/src/util/html.util.js +158 -0
  109. package/dist/src/util/html.util.js.map +1 -0
  110. package/dist/src/util/logger.util.d.ts +26 -0
  111. package/dist/src/util/logger.util.js +80 -0
  112. package/dist/src/util/logger.util.js.map +1 -0
  113. package/dist/src/util/widget-resolve.util.d.ts +52 -0
  114. package/dist/src/util/widget-resolve.util.js +149 -0
  115. package/dist/src/util/widget-resolve.util.js.map +1 -0
  116. package/dist/src/widget/breadcrumb.widget.d.ts +48 -0
  117. package/dist/src/widget/breadcrumb.widget.js +72 -0
  118. package/dist/src/widget/breadcrumb.widget.js.map +1 -0
  119. package/dist/src/widget/page-title.widget.d.ts +33 -0
  120. package/dist/src/widget/page-title.widget.js +33 -0
  121. package/dist/src/widget/page-title.widget.js.map +1 -0
  122. package/dist/src/widget/widget.parser.d.ts +26 -0
  123. package/dist/src/widget/widget.parser.js +76 -0
  124. package/dist/src/widget/widget.parser.js.map +1 -0
  125. package/dist/src/widget/widget.registry.d.ts +23 -0
  126. package/dist/src/widget/widget.registry.js +42 -0
  127. package/dist/src/widget/widget.registry.js.map +1 -0
  128. package/package.json +72 -13
@@ -0,0 +1,307 @@
1
+ /**
2
+ * Overlay Service
3
+ *
4
+ * Programmatic API for modals, toasts, and popovers. For simple trigger
5
+ * patterns, use declarative HTML (commandfor/command + popover/dialog)
6
+ * with zero JS. This service covers dynamic content, programmatic
7
+ * triggers, and complex workflows.
8
+ *
9
+ * dismissAll() is DOM-aware: it closes both programmatic overlays
10
+ * managed by this service AND declarative popovers/dialogs found
11
+ * via DOM queries.
12
+ */
13
+ import { overlayCSS } from "./overlay.css.js";
14
+ const ANIMATION_SAFETY_TIMEOUT = 300;
15
+ /**
16
+ * Animate an element out by setting `data-dismissing`, waiting for
17
+ * `transitionend`, then calling the provided callback. Includes a
18
+ * safety timeout in case the transition event never fires.
19
+ */
20
+ function animateDismiss(el, onDone) {
21
+ el.setAttribute('data-dismissing', '');
22
+ let done = false;
23
+ const finish = () => {
24
+ if (done)
25
+ return;
26
+ done = true;
27
+ onDone();
28
+ };
29
+ el.addEventListener('transitionend', finish, { once: true });
30
+ setTimeout(finish, ANIMATION_SAFETY_TIMEOUT);
31
+ }
32
+ export function createOverlayService() {
33
+ let styleInjected = false;
34
+ // Modal state
35
+ let dialog = null;
36
+ // Uses `any` because modalResolve is reassigned across multiple modal() calls
37
+ // with different type parameters T. Each call creates a Promise.withResolvers<T>(),
38
+ // so the resolver function signature changes (accepts T | PromiseLike<T | undefined>).
39
+ // Type safety is maintained by closeModal<T>(value?: T) which ensures only valid
40
+ // types are passed to the resolver.
41
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
42
+ let modalResolve = null;
43
+ let modalOnClose;
44
+ // Toast state
45
+ let toastContainer = null;
46
+ // Popover state
47
+ let popoverEl = null;
48
+ let popoverAnchorObserver = null;
49
+ const supportsAnchor = typeof CSS !== 'undefined' &&
50
+ CSS.supports('anchor-name', '--a');
51
+ function injectCSS() {
52
+ if (styleInjected)
53
+ return;
54
+ styleInjected = true;
55
+ const style = document.createElement('style');
56
+ style.textContent = overlayCSS;
57
+ document.head.appendChild(style);
58
+ }
59
+ function ensureDialog() {
60
+ if (dialog)
61
+ return dialog;
62
+ injectCSS();
63
+ dialog = document.createElement('dialog');
64
+ dialog.setAttribute('data-overlay-modal', '');
65
+ document.body.appendChild(dialog);
66
+ dialog.addEventListener('click', (e) => {
67
+ if (e.target === dialog) {
68
+ closeModal(undefined);
69
+ }
70
+ });
71
+ return dialog;
72
+ }
73
+ function ensureToastContainer() {
74
+ if (toastContainer)
75
+ return toastContainer;
76
+ injectCSS();
77
+ toastContainer = document.createElement('div');
78
+ toastContainer.setAttribute('data-overlay-toast-container', '');
79
+ document.body.appendChild(toastContainer);
80
+ return toastContainer;
81
+ }
82
+ function ensurePopover() {
83
+ if (popoverEl)
84
+ return popoverEl;
85
+ injectCSS();
86
+ popoverEl = document.createElement('div');
87
+ popoverEl.setAttribute('data-overlay-popover', '');
88
+ popoverEl.setAttribute('popover', '');
89
+ document.body.appendChild(popoverEl);
90
+ return popoverEl;
91
+ }
92
+ // --- Modal ---
93
+ function modal(options) {
94
+ const d = ensureDialog();
95
+ // Clean up any lingering dismiss state from a previous close
96
+ d.removeAttribute('data-dismissing');
97
+ // Immediately dismiss popover — modal takes over the top layer
98
+ hidePopoverImmediate();
99
+ // Last wins: close current modal if open
100
+ if (d.open) {
101
+ d.close();
102
+ if (modalResolve) {
103
+ modalResolve(undefined);
104
+ modalResolve = null;
105
+ }
106
+ if (modalOnClose) {
107
+ modalOnClose();
108
+ modalOnClose = undefined;
109
+ }
110
+ }
111
+ d.innerHTML = '';
112
+ options.render(d);
113
+ modalOnClose = options.onClose;
114
+ const { promise, resolve } = Promise.withResolvers();
115
+ modalResolve = resolve;
116
+ d.showModal();
117
+ return promise;
118
+ }
119
+ function closeModal(value) {
120
+ if (!dialog || !dialog.open)
121
+ return;
122
+ const resolve = modalResolve;
123
+ const onClose = modalOnClose;
124
+ const dialogRef = dialog;
125
+ modalResolve = null;
126
+ modalOnClose = undefined;
127
+ animateDismiss(dialogRef, () => {
128
+ if (dialogRef && dialogRef.open) {
129
+ dialogRef.close();
130
+ if (resolve)
131
+ resolve(value);
132
+ if (onClose)
133
+ onClose();
134
+ }
135
+ });
136
+ }
137
+ // --- Toast ---
138
+ /** Remove dead toasts (dismissed or animation-finished) from container. */
139
+ function clearDeadToasts(container) {
140
+ for (const child of [...container.children]) {
141
+ const el = child;
142
+ if (el.hasAttribute('data-dismissing')) {
143
+ el.remove();
144
+ }
145
+ }
146
+ }
147
+ function toast(options) {
148
+ const container = ensureToastContainer();
149
+ // Clean up dead toasts before adding a new one
150
+ clearDeadToasts(container);
151
+ const el = document.createElement('div');
152
+ el.setAttribute('data-overlay-toast', '');
153
+ const timeout = options.timeout ?? 0;
154
+ if (timeout === 0) {
155
+ el.setAttribute('data-toast-manual', '');
156
+ }
157
+ else {
158
+ el.style.setProperty('--overlay-toast-duration', `${timeout}ms`);
159
+ }
160
+ options.render(el);
161
+ container.appendChild(el);
162
+ let dismissed = false;
163
+ const dismiss = () => {
164
+ if (dismissed)
165
+ return;
166
+ dismissed = true;
167
+ el.setAttribute('data-dismissing', '');
168
+ };
169
+ return { dismiss };
170
+ }
171
+ // --- Popover ---
172
+ function popover(options) {
173
+ const el = ensurePopover();
174
+ // Last wins: hide current popover if showing
175
+ cleanupPopoverAnchorObserver();
176
+ try {
177
+ el.hidePopover();
178
+ }
179
+ catch {
180
+ // Not shown — ignore
181
+ }
182
+ el.removeAttribute('data-dismissing');
183
+ el.innerHTML = '';
184
+ options.render(el);
185
+ // Anchor positioning
186
+ if (supportsAnchor) {
187
+ const anchorName = '--overlay-anchor';
188
+ options.anchor.style.setProperty('anchor-name', anchorName);
189
+ el.style.setProperty('position-anchor', anchorName);
190
+ el.style.removeProperty('top');
191
+ el.style.removeProperty('left');
192
+ }
193
+ else {
194
+ const rect = options.anchor.getBoundingClientRect();
195
+ el.style.top = `${rect.bottom + globalThis.scrollY}px`;
196
+ el.style.left = `${rect.left + globalThis.scrollX}px`;
197
+ el.style.position = 'absolute';
198
+ }
199
+ el.showPopover();
200
+ // Watch for anchor disconnect
201
+ watchAnchorDisconnect(options.anchor);
202
+ }
203
+ function watchAnchorDisconnect(anchor) {
204
+ cleanupPopoverAnchorObserver();
205
+ const parent = anchor.parentNode;
206
+ if (!parent) {
207
+ closePopover();
208
+ return;
209
+ }
210
+ popoverAnchorObserver = new MutationObserver(() => {
211
+ if (!document.contains(anchor)) {
212
+ closePopover();
213
+ }
214
+ });
215
+ popoverAnchorObserver.observe(parent, { childList: true });
216
+ }
217
+ /** Hide popover instantly without dismiss animation. */
218
+ function hidePopoverImmediate() {
219
+ cleanupPopoverAnchorObserver();
220
+ if (!popoverEl)
221
+ return;
222
+ try {
223
+ popoverEl.hidePopover();
224
+ }
225
+ catch {
226
+ // Not shown — ignore
227
+ }
228
+ popoverEl.removeAttribute('data-dismissing');
229
+ }
230
+ function cleanupPopoverAnchorObserver() {
231
+ if (popoverAnchorObserver) {
232
+ popoverAnchorObserver.disconnect();
233
+ popoverAnchorObserver = null;
234
+ }
235
+ }
236
+ function closePopover() {
237
+ cleanupPopoverAnchorObserver();
238
+ if (!popoverEl)
239
+ return;
240
+ // Check if popover is showing via matches(':popover-open')
241
+ let isOpen;
242
+ try {
243
+ isOpen = popoverEl.matches(':popover-open');
244
+ }
245
+ catch {
246
+ // :popover-open may not be supported — fall back
247
+ isOpen = popoverEl.hasAttribute('popover') && popoverEl.style.display !== 'none';
248
+ }
249
+ if (!isOpen)
250
+ return;
251
+ animateDismiss(popoverEl, () => {
252
+ try {
253
+ popoverEl.hidePopover();
254
+ }
255
+ catch {
256
+ // Already hidden
257
+ }
258
+ });
259
+ }
260
+ // --- Dismiss all ---
261
+ function dismissAll() {
262
+ // Close programmatic modal
263
+ if (dialog && dialog.open) {
264
+ const resolve = modalResolve;
265
+ const onClose = modalOnClose;
266
+ modalResolve = null;
267
+ modalOnClose = undefined;
268
+ dialog.removeAttribute('data-dismissing');
269
+ dialog.close();
270
+ if (resolve)
271
+ resolve(undefined);
272
+ if (onClose)
273
+ onClose();
274
+ }
275
+ // Hide programmatic popover
276
+ hidePopoverImmediate();
277
+ // Dismiss all toasts via CSS
278
+ if (toastContainer) {
279
+ for (const child of toastContainer.children) {
280
+ child.setAttribute('data-dismissing', '');
281
+ }
282
+ }
283
+ // Close declarative popovers found in the DOM
284
+ try {
285
+ for (const el of document.querySelectorAll(':popover-open')) {
286
+ el.hidePopover();
287
+ }
288
+ }
289
+ catch {
290
+ // :popover-open not supported
291
+ }
292
+ // Close declarative dialogs found in the DOM (skip our own)
293
+ for (const el of document.querySelectorAll('dialog[open]')) {
294
+ if (el !== dialog)
295
+ el.close();
296
+ }
297
+ }
298
+ return {
299
+ modal,
300
+ closeModal,
301
+ toast,
302
+ popover,
303
+ closePopover,
304
+ dismissAll,
305
+ };
306
+ }
307
+ //# sourceMappingURL=overlay.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlay.service.js","sourceRoot":"","sources":["../../../src/overlay/overlay.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Overlay Service Types
3
+ *
4
+ * Programmatic API for overlays. For simple cases, use declarative HTML
5
+ * attributes (commandfor/command + popover/dialog) — zero JS required.
6
+ * This service provides the imperative path for dynamic content,
7
+ * programmatic triggers, and complex workflows. dismissAll() is
8
+ * DOM-aware and closes both programmatic and declarative overlays.
9
+ */
10
+ export interface OverlayService {
11
+ modal<T = undefined>(options: ModalOptions<T>): Promise<T | undefined>;
12
+ closeModal<T>(value?: T): void;
13
+ popover(options: PopoverOptions): void;
14
+ closePopover(): void;
15
+ toast(options: ToastOptions): {
16
+ dismiss(): void;
17
+ };
18
+ /** Close all open overlays — programmatic and declarative — and toasts. */
19
+ dismissAll(): void;
20
+ }
21
+ export interface ModalOptions<T = undefined> {
22
+ render(dialog: HTMLDialogElement): void;
23
+ onClose?(): void;
24
+ }
25
+ export interface PopoverOptions {
26
+ anchor: HTMLElement;
27
+ render(el: HTMLDivElement): void;
28
+ }
29
+ export interface ToastOptions {
30
+ render(el: HTMLDivElement): void;
31
+ /** Auto-dismiss timeout in ms. Default 0 (manual dismiss only). Set to a positive ms value for auto-dismiss via CSS animation. */
32
+ timeout?: number;
33
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Overlay Service Types
3
+ *
4
+ * Programmatic API for overlays. For simple cases, use declarative HTML
5
+ * attributes (commandfor/command + popover/dialog) — zero JS required.
6
+ * This service provides the imperative path for dynamic content,
7
+ * programmatic triggers, and complex workflows. dismissAll() is
8
+ * DOM-aware and closes both programmatic and declarative overlays.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=overlay.type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlay.type.js","sourceRoot":"","sources":["../../../src/overlay/overlay.type.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Base Renderer
3
+ *
4
+ * Shared rendering logic for SPA and Hash routers:
5
+ * - Route hierarchy traversal with nested slot rendering
6
+ * - Component loading, data fetching, and HTML rendering
7
+ * - Markdown render waiting
8
+ * - Document title updates
9
+ */
10
+ import type { MatchedRoute, RouteConfig, RouteInfo } from '../../type/route.type.ts';
11
+ import { RouteCore } from '../../route/route.core.ts';
12
+ /**
13
+ * Abstract base for renderers that share the page rendering pipeline.
14
+ * Subclasses provide navigation mechanics (Navigation API, hashchange, etc.).
15
+ */
16
+ export declare abstract class BaseRenderer {
17
+ protected core: RouteCore;
18
+ protected slot: Element | null;
19
+ constructor(core: RouteCore);
20
+ /**
21
+ * Render a matched page route with nested route support.
22
+ */
23
+ protected renderPage(routeInfo: RouteInfo, matched: MatchedRoute, signal: AbortSignal): Promise<void>;
24
+ /**
25
+ * Render a single route's content.
26
+ */
27
+ protected renderRouteContent(routeInfo: RouteInfo, route: RouteConfig, signal: AbortSignal, isLeaf?: boolean): Promise<{
28
+ html: string;
29
+ title?: string;
30
+ }>;
31
+ /**
32
+ * Wait for a <mark-down> element to finish rendering.
33
+ */
34
+ protected waitForMarkdownRender(element: HTMLElement): Promise<void>;
35
+ /**
36
+ * Update document.title from getTitle() result.
37
+ */
38
+ protected updateTitle(pageTitle?: string): void;
39
+ }
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Base Renderer
3
+ *
4
+ * Shared rendering logic for SPA and Hash routers:
5
+ * - Route hierarchy traversal with nested slot rendering
6
+ * - Component loading, data fetching, and HTML rendering
7
+ * - Markdown render waiting
8
+ * - Document title updates
9
+ */
10
+ import defaultPageComponent from "../../component/page.component.js";
11
+ import { DEFAULT_ROOT_ROUTE } from "../../route/route.core.js";
12
+ import { logger } from "../../util/logger.util.js";
13
+ const MARKDOWN_RENDER_TIMEOUT = 5000;
14
+ /**
15
+ * Abstract base for renderers that share the page rendering pipeline.
16
+ * Subclasses provide navigation mechanics (Navigation API, hashchange, etc.).
17
+ */
18
+ export class BaseRenderer {
19
+ core;
20
+ slot = null;
21
+ constructor(core) {
22
+ this.core = core;
23
+ }
24
+ /**
25
+ * Render a matched page route with nested route support.
26
+ */
27
+ async renderPage(routeInfo, matched, signal) {
28
+ if (!this.slot)
29
+ return;
30
+ try {
31
+ const hierarchy = this.core.buildRouteHierarchy(routeInfo.pattern);
32
+ logger.render('page', routeInfo.pattern, `hierarchy: ${hierarchy.join(' > ')}`);
33
+ let currentSlot = this.slot;
34
+ let pageTitle;
35
+ for (let i = 0; i < hierarchy.length; i++) {
36
+ if (signal.aborted)
37
+ return;
38
+ const routePattern = hierarchy[i];
39
+ const isLeaf = i === hierarchy.length - 1;
40
+ let route = this.core.matcher.findRoute(routePattern);
41
+ if (!route && routePattern === this.core.root) {
42
+ route = { ...DEFAULT_ROOT_ROUTE, pattern: this.core.root };
43
+ }
44
+ if (!route) {
45
+ logger.render('skip', routePattern, 'route not found');
46
+ continue;
47
+ }
48
+ const routeType = isLeaf ? 'leaf' : 'layout';
49
+ logger.render(routeType, routePattern, `${route.files?.ts ?? 'default'} → slot`);
50
+ // Skip wildcard route appearing as its own parent (prevents double-render)
51
+ if (route === matched.route && routePattern !== matched.route.pattern) {
52
+ continue;
53
+ }
54
+ const { html, title } = await this.renderRouteContent(routeInfo, route, signal, isLeaf);
55
+ if (signal.aborted)
56
+ return;
57
+ currentSlot.setHTMLUnsafe(html);
58
+ if (title) {
59
+ pageTitle = title;
60
+ }
61
+ // Wait for <mark-down> to finish rendering its content
62
+ // (must happen before attributing slots — router-slot may be inside markdown)
63
+ const markDown = currentSlot.querySelector('mark-down');
64
+ if (markDown) {
65
+ await this.waitForMarkdownRender(markDown);
66
+ if (signal.aborted)
67
+ return;
68
+ }
69
+ // Attribute bare <router-slot> tags with this route's pattern
70
+ for (const slot of currentSlot.querySelectorAll('router-slot:not([pattern])')) {
71
+ slot.setAttribute('pattern', routePattern);
72
+ }
73
+ if (!isLeaf) {
74
+ const nestedSlot = currentSlot.querySelector(`router-slot[pattern="${CSS.escape(routePattern)}"]`);
75
+ if (nestedSlot) {
76
+ currentSlot = nestedSlot;
77
+ }
78
+ else {
79
+ logger.warn(`Route "${routePattern}" has no <router-slot> ` +
80
+ `for child routes to render into. ` +
81
+ `Add <router-slot></router-slot> to the parent template.`);
82
+ }
83
+ }
84
+ }
85
+ if (signal.aborted)
86
+ return;
87
+ this.updateTitle(pageTitle);
88
+ this.core.emit({
89
+ type: 'load',
90
+ pathname: routeInfo.pattern,
91
+ params: routeInfo.params,
92
+ });
93
+ }
94
+ catch (error) {
95
+ if (signal.aborted)
96
+ return;
97
+ throw error;
98
+ }
99
+ }
100
+ /**
101
+ * Render a single route's content.
102
+ */
103
+ async renderRouteContent(routeInfo, route, signal, isLeaf) {
104
+ if (route.modulePath === DEFAULT_ROOT_ROUTE.modulePath) {
105
+ return { html: `<router-slot pattern="${route.pattern}"></router-slot>` };
106
+ }
107
+ const files = route.files ?? {};
108
+ const component = files.ts
109
+ ? (await this.core.loadModule(files.ts)).default
110
+ : defaultPageComponent;
111
+ const context = await this.core.buildComponentContext(routeInfo, route, signal, isLeaf);
112
+ const data = await component.getData({ params: routeInfo.params, signal, context });
113
+ const html = component.renderHTML({ data, params: routeInfo.params, context });
114
+ const title = component.getTitle({ data, params: routeInfo.params, context });
115
+ return { html, title };
116
+ }
117
+ /**
118
+ * Wait for a <mark-down> element to finish rendering.
119
+ */
120
+ waitForMarkdownRender(element) {
121
+ return new Promise((resolve) => {
122
+ if (element.children.length > 0) {
123
+ resolve();
124
+ return;
125
+ }
126
+ const timeout = setTimeout(() => {
127
+ observer.disconnect();
128
+ resolve();
129
+ }, MARKDOWN_RENDER_TIMEOUT);
130
+ const observer = new MutationObserver(() => {
131
+ if (element.children.length > 0) {
132
+ clearTimeout(timeout);
133
+ observer.disconnect();
134
+ resolve();
135
+ }
136
+ });
137
+ observer.observe(element, { childList: true });
138
+ });
139
+ }
140
+ /**
141
+ * Update document.title from getTitle() result.
142
+ */
143
+ updateTitle(pageTitle) {
144
+ if (pageTitle) {
145
+ document.title = pageTitle;
146
+ }
147
+ }
148
+ }
149
+ //# sourceMappingURL=base.renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.renderer.js","sourceRoot":"","sources":["../../../../src/renderer/spa/base.renderer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Hash Router
3
+ *
4
+ * Lightweight client-side router for leaf mode mini-apps.
5
+ * Uses hashchange events + RouteCore pattern matching.
6
+ *
7
+ * Routes are defined inline by the consumer, not from the main manifest.
8
+ * Coexists with SpaHtmlRouter in root mode (SPA router skips hash changes).
9
+ */
10
+ import type { RoutesManifest } from '../../type/route.type.ts';
11
+ import type { ContextProvider } from '../../component/abstract.component.ts';
12
+ import { RouteCore } from '../../route/route.core.ts';
13
+ import { BaseRenderer } from './base.renderer.ts';
14
+ /**
15
+ * A single hash route definition with a lazy module loader.
16
+ * @experimental
17
+ */
18
+ export interface HashRouteConfig {
19
+ /** URLPattern pathname pattern (e.g. '/settings', '/users/:id'). */
20
+ pattern: string;
21
+ /** Lazy loader returning a module with a default PageComponent export. */
22
+ loader: () => Promise<unknown>;
23
+ }
24
+ /**
25
+ * Options for creating a HashRouter.
26
+ * @experimental
27
+ */
28
+ export interface HashRouterOptions {
29
+ /** Inline route definitions. */
30
+ routes: HashRouteConfig[];
31
+ /** CSS selector or element to render into. Defaults to 'hash-slot'. */
32
+ slot?: string | Element;
33
+ /** Enriches every ComponentContext with app-level services. */
34
+ extendContext?: ContextProvider;
35
+ }
36
+ /**
37
+ * Hash-based mini-app router for leaf mode pages.
38
+ *
39
+ * Listens to `hashchange`, maps `#/path` → pattern match via RouteCore,
40
+ * renders matched PageComponent into a slot element.
41
+ *
42
+ * @experimental
43
+ */
44
+ export declare class HashRouter extends BaseRenderer {
45
+ private boundHandler;
46
+ constructor(manifest: RoutesManifest, options?: {
47
+ extendContext?: ContextProvider;
48
+ });
49
+ /**
50
+ * Initialize: find slot, attach hashchange listener, render initial hash.
51
+ */
52
+ initialize(slot?: string | Element): Promise<void>;
53
+ /**
54
+ * Navigate to a hash path. Triggers hashchange → render.
55
+ */
56
+ navigate(hash: string): void;
57
+ /**
58
+ * Add event listener for router events.
59
+ */
60
+ addEventListener(listener: Parameters<RouteCore['addEventListener']>[0]): () => void;
61
+ /**
62
+ * Remove event listeners and release references.
63
+ */
64
+ dispose(): void;
65
+ /**
66
+ * Handle a hashchange event: parse hash, match, render.
67
+ */
68
+ private handleHashChange;
69
+ }
70
+ /**
71
+ * Create and initialize a hash router for a leaf-mode mini-app.
72
+ *
73
+ * The router instance is stored on `globalThis.__emroute_hash_router` for
74
+ * programmatic access. Calling twice returns the existing router with a warning.
75
+ *
76
+ * @experimental
77
+ */
78
+ export declare function createHashRouter(options: HashRouterOptions): Promise<HashRouter>;