slicejs-web-framework 3.3.7 → 3.4.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.
- package/.opencode/opencode.json +14 -13
- package/Slice/Components/Structural/ContextManager/ContextManager.js +422 -423
- package/Slice/Components/Structural/ContextManager/ContextManagerDebugger.js +470 -420
- package/Slice/Components/Structural/Controller/Controller.js +1198 -1199
- package/Slice/Components/Structural/Debugger/Debugger.js +1505 -1497
- package/Slice/Components/Structural/EventManager/EventManager.js +366 -338
- package/Slice/Components/Structural/EventManager/EventManagerDebugger.js +210 -39
- package/Slice/Components/Structural/Logger/LogViewer/LogViewer.js +541 -0
- package/Slice/Components/Structural/Logger/Logger.js +225 -145
- package/Slice/Components/Structural/Router/Router.js +775 -760
- package/Slice/Components/Structural/StylesManager/StylesManager.js +82 -82
- package/Slice/Components/Structural/StylesManager/ThemeManager/ThemeManager.js +106 -106
- package/Slice/Slice.js +632 -618
- package/Slice/tests/build-singleton.test.js +244 -244
- package/Slice/tests/bundle-v2-runtime-contract.test.js +738 -728
- package/Slice/tests/context-patch-use.test.js +95 -95
- package/Slice/tests/fixtures/real-runtime-loader.mjs +21 -21
- package/Slice/tests/public-env-typed-accessors.test.js +66 -66
- package/api/index.js +281 -286
- package/api/utils/publicEnvResolver.js +123 -117
- package/package.json +44 -44
|
@@ -6,7 +6,10 @@ export default class EventManagerDebugger extends HTMLElement {
|
|
|
6
6
|
super();
|
|
7
7
|
this.isOpen = false;
|
|
8
8
|
this.filterText = '';
|
|
9
|
+
this.activeTab = 'subscribers';
|
|
9
10
|
this.refreshInterval = null;
|
|
11
|
+
this._autoRefreshTimer = null;
|
|
12
|
+
this._lastHistoryLength = 0;
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
/**
|
|
@@ -41,6 +44,11 @@ export default class EventManagerDebugger extends HTMLElement {
|
|
|
41
44
|
open() {
|
|
42
45
|
this.isOpen = true;
|
|
43
46
|
this.container.classList.add('active');
|
|
47
|
+
this.activeTab = 'subscribers';
|
|
48
|
+
if (slice.events) {
|
|
49
|
+
slice.events.startRecording();
|
|
50
|
+
}
|
|
51
|
+
this._startAutoRefresh();
|
|
44
52
|
this.renderList();
|
|
45
53
|
}
|
|
46
54
|
|
|
@@ -51,6 +59,29 @@ export default class EventManagerDebugger extends HTMLElement {
|
|
|
51
59
|
close() {
|
|
52
60
|
this.isOpen = false;
|
|
53
61
|
this.container.classList.remove('active');
|
|
62
|
+
this._stopAutoRefresh();
|
|
63
|
+
if (slice.events) {
|
|
64
|
+
slice.events.stopRecording();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
_startAutoRefresh() {
|
|
69
|
+
this._stopAutoRefresh();
|
|
70
|
+
this._autoRefreshTimer = setInterval(() => {
|
|
71
|
+
if (!this.isOpen) return;
|
|
72
|
+
if (this.activeTab === 'history') {
|
|
73
|
+
this.renderHistory();
|
|
74
|
+
} else {
|
|
75
|
+
this.renderList();
|
|
76
|
+
}
|
|
77
|
+
}, 1500);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
_stopAutoRefresh() {
|
|
81
|
+
if (this._autoRefreshTimer) {
|
|
82
|
+
clearInterval(this._autoRefreshTimer);
|
|
83
|
+
this._autoRefreshTimer = null;
|
|
84
|
+
}
|
|
54
85
|
}
|
|
55
86
|
|
|
56
87
|
cacheElements() {
|
|
@@ -61,15 +92,35 @@ export default class EventManagerDebugger extends HTMLElement {
|
|
|
61
92
|
this.countLabel = this.querySelector('#events-count');
|
|
62
93
|
this.refreshButton = this.querySelector('#events-refresh');
|
|
63
94
|
this.closeButton = this.querySelector('#events-close');
|
|
95
|
+
this.tabSubs = this.querySelector('#tab-subscribers');
|
|
96
|
+
this.tabHistory = this.querySelector('#tab-history');
|
|
64
97
|
}
|
|
65
98
|
|
|
66
99
|
bindEvents() {
|
|
67
|
-
this.refreshButton.addEventListener('click', () =>
|
|
100
|
+
this.refreshButton.addEventListener('click', () => {
|
|
101
|
+
if (this.activeTab === 'history') this.renderHistory();
|
|
102
|
+
else this.renderList();
|
|
103
|
+
});
|
|
68
104
|
this.closeButton.addEventListener('click', () => this.close());
|
|
69
105
|
this.filterInput.addEventListener('input', (event) => {
|
|
70
106
|
this.filterText = event.target.value.trim().toLowerCase();
|
|
107
|
+
if (this.activeTab === 'history') this.renderHistory();
|
|
108
|
+
else this.renderList();
|
|
109
|
+
});
|
|
110
|
+
this.tabSubs.addEventListener('click', () => {
|
|
111
|
+
this.activeTab = 'subscribers';
|
|
112
|
+
this.tabSubs.classList.add('active');
|
|
113
|
+
this.tabHistory.classList.remove('active');
|
|
114
|
+
this.filterInput.placeholder = 'filter events…';
|
|
71
115
|
this.renderList();
|
|
72
116
|
});
|
|
117
|
+
this.tabHistory.addEventListener('click', () => {
|
|
118
|
+
this.activeTab = 'history';
|
|
119
|
+
this.tabHistory.classList.add('active');
|
|
120
|
+
this.tabSubs.classList.remove('active');
|
|
121
|
+
this.filterInput.placeholder = 'filter history…';
|
|
122
|
+
this.renderHistory();
|
|
123
|
+
});
|
|
73
124
|
}
|
|
74
125
|
|
|
75
126
|
makeDraggable() {
|
|
@@ -117,6 +168,7 @@ export default class EventManagerDebugger extends HTMLElement {
|
|
|
117
168
|
|
|
118
169
|
const items = [];
|
|
119
170
|
slice.events.subscriptions.forEach((subs, eventName) => {
|
|
171
|
+
const emitCount = slice.events.emitCounts?.get(eventName) || 0;
|
|
120
172
|
const entries = Array.from(subs.entries()).map(([id, sub]) => {
|
|
121
173
|
const componentSliceId = sub.componentSliceId || null;
|
|
122
174
|
const component = componentSliceId ? slice.controller.getComponent(componentSliceId) : null;
|
|
@@ -133,7 +185,7 @@ export default class EventManagerDebugger extends HTMLElement {
|
|
|
133
185
|
return;
|
|
134
186
|
}
|
|
135
187
|
|
|
136
|
-
items.push({ eventName, count: subs.size, entries });
|
|
188
|
+
items.push({ eventName, count: subs.size, emitCount, entries });
|
|
137
189
|
});
|
|
138
190
|
|
|
139
191
|
items.sort((a, b) => a.eventName.localeCompare(b.eventName));
|
|
@@ -141,32 +193,76 @@ export default class EventManagerDebugger extends HTMLElement {
|
|
|
141
193
|
this.countLabel.textContent = String(items.length);
|
|
142
194
|
this.list.innerHTML = items.length
|
|
143
195
|
? items.map((item) => {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
196
|
+
const details = item.entries.map((entry) => {
|
|
197
|
+
const label = entry.componentName
|
|
198
|
+
? `${entry.componentName} (${entry.componentSliceId})`
|
|
199
|
+
: entry.componentSliceId || 'Global';
|
|
200
|
+
const onceBadge = entry.once ? '<span class="badge">once</span>' : '';
|
|
201
|
+
return `
|
|
202
|
+
<div class="subscriber-row">
|
|
203
|
+
<div class="subscriber-name">${label}</div>
|
|
204
|
+
<div class="subscriber-meta">${entry.id}${onceBadge}</div>
|
|
205
|
+
</div>
|
|
206
|
+
`;
|
|
207
|
+
}).join('');
|
|
208
|
+
|
|
209
|
+
return `
|
|
210
|
+
<details class="event-row">
|
|
211
|
+
<summary>
|
|
212
|
+
<div class="event-name">${item.eventName}</div>
|
|
213
|
+
<div class="event-metrics">
|
|
214
|
+
<span class="emit-count" title="Emits this session">⚡${item.emitCount}</span>
|
|
215
|
+
<span class="event-count">${item.count}</span>
|
|
216
|
+
</div>
|
|
217
|
+
</summary>
|
|
218
|
+
<div class="subscriber-list">
|
|
219
|
+
${details || '<div class="empty">No subscribers</div>'}
|
|
220
|
+
</div>
|
|
221
|
+
</details>
|
|
222
|
+
`;
|
|
223
|
+
}).join('')
|
|
224
|
+
: '<div class="empty">No events</div>';
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
renderHistory() {
|
|
228
|
+
if (!slice?.events?.emitHistory) {
|
|
229
|
+
this.list.textContent = 'EventManager not available.';
|
|
230
|
+
this.countLabel.textContent = '0';
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const history = slice.events.emitHistory;
|
|
235
|
+
const filtered = this.filterText
|
|
236
|
+
? history.filter(e => e.eventName.toLowerCase().includes(this.filterText))
|
|
237
|
+
: history;
|
|
238
|
+
|
|
239
|
+
this.countLabel.textContent = String(filtered.length);
|
|
240
|
+
if (!filtered.length) {
|
|
241
|
+
this.list.innerHTML = '<div class="empty">No emits recorded yet</div>';
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const now = Date.now();
|
|
246
|
+
this.list.innerHTML = [...filtered].reverse().map((entry) => {
|
|
247
|
+
const diff = now - entry.timestamp;
|
|
248
|
+
const timeStr = diff < 1000 ? 'now'
|
|
249
|
+
: diff < 60000 ? `${Math.floor(diff / 1000)}s ago`
|
|
250
|
+
: `${Math.floor(diff / 60000)}m ago`;
|
|
251
|
+
return `
|
|
252
|
+
<div class="history-row">
|
|
253
|
+
<div class="history-event">${this.escapeHtml(entry.eventName)}</div>
|
|
254
|
+
<div class="history-time">${timeStr}</div>
|
|
255
|
+
</div>
|
|
256
|
+
`;
|
|
257
|
+
}).join('');
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
escapeHtml(value) {
|
|
261
|
+
return String(value)
|
|
262
|
+
.replace(/&/g, '&')
|
|
263
|
+
.replace(/</g, '<')
|
|
264
|
+
.replace(/>/g, '>')
|
|
265
|
+
.replace(/"/g, '"');
|
|
170
266
|
}
|
|
171
267
|
|
|
172
268
|
renderTemplate() {
|
|
@@ -183,6 +279,10 @@ export default class EventManagerDebugger extends HTMLElement {
|
|
|
183
279
|
<button id="events-close" class="btn" title="Close" aria-label="Close">✕</button>
|
|
184
280
|
</div>
|
|
185
281
|
</div>
|
|
282
|
+
<div class="events-tabs">
|
|
283
|
+
<button id="tab-subscribers" class="tab-btn active">Subscribers</button>
|
|
284
|
+
<button id="tab-history" class="tab-btn">History</button>
|
|
285
|
+
</div>
|
|
186
286
|
<div class="events-toolbar">
|
|
187
287
|
<input id="events-filter" type="text" placeholder="filter events…" autocomplete="off" spellcheck="false" />
|
|
188
288
|
<div class="count"><span id="events-count">0</span></div>
|
|
@@ -195,18 +295,22 @@ export default class EventManagerDebugger extends HTMLElement {
|
|
|
195
295
|
renderStyles() {
|
|
196
296
|
return `
|
|
197
297
|
/* Slice Instruments — events console. All selectors scoped to the
|
|
198
|
-
|
|
298
|
+
<slice-eventmanager-debugger> tag so nothing clashes with app styles.
|
|
299
|
+
Every --si-* token reads the matching framework theme variable from
|
|
300
|
+
:root, falling back to the original hardcoded value if absent. */
|
|
199
301
|
slice-eventmanager-debugger {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
302
|
+
--si-accent: var(--primary-color, #6ee7ff);
|
|
303
|
+
--si-accent-rgb: var(--primary-color-rgb, 110, 231, 255);
|
|
304
|
+
--si-surface: var(--primary-background-color, rgba(17, 19, 28, 0.86));
|
|
305
|
+
--si-raised: var(--secondary-background-color, rgba(255, 255, 255, 0.035));
|
|
306
|
+
--si-raised-2: var(--tertiary-background-color, rgba(255, 255, 255, 0.06));
|
|
307
|
+
--si-border: var(--medium-color, rgba(255, 255, 255, 0.09));
|
|
308
|
+
--si-text: var(--font-primary-color, #e8eaf2);
|
|
309
|
+
--si-dim: var(--font-secondary-color, #888fa6);
|
|
310
|
+
--si-danger: var(--danger-color, #ff6b6b);
|
|
311
|
+
--si-success: var(--success-color, #46d39a);
|
|
312
|
+
--si-mono: ui-monospace, 'SF Mono', 'JetBrains Mono', 'Cascadia Code', Menlo, Consolas, monospace;
|
|
313
|
+
}
|
|
210
314
|
|
|
211
315
|
slice-eventmanager-debugger #events-debugger {
|
|
212
316
|
position: fixed;
|
|
@@ -311,6 +415,31 @@ slice-eventmanager-debugger .btn:hover {
|
|
|
311
415
|
slice-eventmanager-debugger .btn:active { transform: scale(0.92); }
|
|
312
416
|
slice-eventmanager-debugger #events-refresh:hover { color: var(--si-accent); }
|
|
313
417
|
|
|
418
|
+
slice-eventmanager-debugger .events-tabs {
|
|
419
|
+
display: flex;
|
|
420
|
+
gap: 0;
|
|
421
|
+
padding: 0 12px;
|
|
422
|
+
border-bottom: 1px solid var(--si-border);
|
|
423
|
+
background: var(--si-raised);
|
|
424
|
+
}
|
|
425
|
+
slice-eventmanager-debugger .tab-btn {
|
|
426
|
+
all: unset;
|
|
427
|
+
cursor: pointer;
|
|
428
|
+
font-size: 10px;
|
|
429
|
+
font-weight: 600;
|
|
430
|
+
letter-spacing: 0.06em;
|
|
431
|
+
text-transform: uppercase;
|
|
432
|
+
padding: 7px 12px;
|
|
433
|
+
color: var(--si-dim);
|
|
434
|
+
border-bottom: 2px solid transparent;
|
|
435
|
+
transition: color 0.15s ease, border-color 0.15s ease;
|
|
436
|
+
}
|
|
437
|
+
slice-eventmanager-debugger .tab-btn:hover { color: var(--si-text); }
|
|
438
|
+
slice-eventmanager-debugger .tab-btn.active {
|
|
439
|
+
color: var(--si-accent);
|
|
440
|
+
border-bottom-color: var(--si-accent);
|
|
441
|
+
}
|
|
442
|
+
|
|
314
443
|
slice-eventmanager-debugger .events-toolbar {
|
|
315
444
|
display: flex;
|
|
316
445
|
gap: 10px;
|
|
@@ -397,6 +526,21 @@ slice-eventmanager-debugger .event-name {
|
|
|
397
526
|
white-space: nowrap;
|
|
398
527
|
}
|
|
399
528
|
|
|
529
|
+
slice-eventmanager-debugger .event-metrics {
|
|
530
|
+
display: flex;
|
|
531
|
+
align-items: center;
|
|
532
|
+
gap: 6px;
|
|
533
|
+
}
|
|
534
|
+
slice-eventmanager-debugger .emit-count {
|
|
535
|
+
font-weight: 600;
|
|
536
|
+
font-size: 10px;
|
|
537
|
+
color: var(--si-success);
|
|
538
|
+
background: rgba(70, 211, 154, 0.12);
|
|
539
|
+
border: 1px solid rgba(70, 211, 154, 0.25);
|
|
540
|
+
padding: 1px 6px;
|
|
541
|
+
border-radius: 999px;
|
|
542
|
+
white-space: nowrap;
|
|
543
|
+
}
|
|
400
544
|
slice-eventmanager-debugger .event-count {
|
|
401
545
|
font-weight: 600;
|
|
402
546
|
font-size: 11px;
|
|
@@ -408,6 +552,33 @@ slice-eventmanager-debugger .event-count {
|
|
|
408
552
|
min-width: 22px;
|
|
409
553
|
text-align: center;
|
|
410
554
|
}
|
|
555
|
+
slice-eventmanager-debugger .history-row {
|
|
556
|
+
display: flex;
|
|
557
|
+
justify-content: space-between;
|
|
558
|
+
align-items: center;
|
|
559
|
+
gap: 10px;
|
|
560
|
+
padding: 6px 11px;
|
|
561
|
+
background: var(--si-raised);
|
|
562
|
+
border-radius: 7px;
|
|
563
|
+
border: 1px solid var(--si-border);
|
|
564
|
+
border-left: 2px solid transparent;
|
|
565
|
+
transition: border-color 0.15s ease;
|
|
566
|
+
}
|
|
567
|
+
slice-eventmanager-debugger .history-row:hover { border-left-color: var(--si-accent); }
|
|
568
|
+
slice-eventmanager-debugger .history-event {
|
|
569
|
+
font-family: var(--si-mono);
|
|
570
|
+
font-size: 11.5px;
|
|
571
|
+
color: var(--si-text);
|
|
572
|
+
overflow: hidden;
|
|
573
|
+
text-overflow: ellipsis;
|
|
574
|
+
white-space: nowrap;
|
|
575
|
+
}
|
|
576
|
+
slice-eventmanager-debugger .history-time {
|
|
577
|
+
font-size: 10px;
|
|
578
|
+
color: var(--si-dim);
|
|
579
|
+
white-space: nowrap;
|
|
580
|
+
flex-shrink: 0;
|
|
581
|
+
}
|
|
411
582
|
|
|
412
583
|
slice-eventmanager-debugger .subscriber-list {
|
|
413
584
|
margin-top: 9px;
|