@vobs/devtools-ui 1.1.0 → 1.2.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/dist/index.cjs +3336 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +3332 -0
- package/dist/index.js.map +1 -0
- package/dist/panel.cjs +3187 -0
- package/dist/panel.cjs.map +1 -0
- package/dist/panel.d.cts +41 -0
- package/dist/panel.d.ts +41 -0
- package/dist/panel.js +3183 -0
- package/dist/panel.js.map +1 -0
- package/dist/styles/styles.css +1582 -0
- package/dist/widget.cjs +3330 -0
- package/dist/widget.cjs.map +1 -0
- package/dist/widget.d.cts +13 -0
- package/dist/widget.d.ts +13 -0
- package/dist/widget.js +3328 -0
- package/dist/widget.js.map +1 -0
- package/package.json +38 -12
package/dist/panel.js
ADDED
|
@@ -0,0 +1,3183 @@
|
|
|
1
|
+
import 'axios';
|
|
2
|
+
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
5
|
+
|
|
6
|
+
// packages/reactivity/src/debug.ts
|
|
7
|
+
var activeDebugHooks = null;
|
|
8
|
+
var signalNames = /* @__PURE__ */ new WeakMap();
|
|
9
|
+
function hasDebugHooks() {
|
|
10
|
+
return activeDebugHooks !== null;
|
|
11
|
+
}
|
|
12
|
+
__name(hasDebugHooks, "hasDebugHooks");
|
|
13
|
+
function setSignalDebugName(signal, name) {
|
|
14
|
+
signalNames.set(signal, name);
|
|
15
|
+
invokeDebug("signalNamed", signal, name);
|
|
16
|
+
}
|
|
17
|
+
__name(setSignalDebugName, "setSignalDebugName");
|
|
18
|
+
function invokeDebug(name, ...args) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
__name(invokeDebug, "invokeDebug");
|
|
22
|
+
|
|
23
|
+
// packages/reactivity/src/owner.ts
|
|
24
|
+
var currentOwner = null;
|
|
25
|
+
var nextOwnerId = 1;
|
|
26
|
+
var ownerNames = /* @__PURE__ */ new WeakMap();
|
|
27
|
+
function createOwner() {
|
|
28
|
+
const parent = currentOwner;
|
|
29
|
+
let disposed = parent?.disposed ?? false;
|
|
30
|
+
const children = [];
|
|
31
|
+
const cleanups = [];
|
|
32
|
+
const errorHandlers = /* @__PURE__ */ new Set();
|
|
33
|
+
const owner = {
|
|
34
|
+
id: `owner-${nextOwnerId++}`,
|
|
35
|
+
parent,
|
|
36
|
+
children,
|
|
37
|
+
depth: (parent?.depth ?? -1) + 1,
|
|
38
|
+
get disposed() {
|
|
39
|
+
return disposed;
|
|
40
|
+
},
|
|
41
|
+
run(fn) {
|
|
42
|
+
if (disposed) throw new Error("Vobs: \u5DF2\u9500\u6BC1\u7684 Owner \u4E0D\u80FD\u7EE7\u7EED\u8FD0\u884C");
|
|
43
|
+
const previous = currentOwner;
|
|
44
|
+
currentOwner = owner;
|
|
45
|
+
try {
|
|
46
|
+
return fn();
|
|
47
|
+
} finally {
|
|
48
|
+
currentOwner = previous;
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
addCleanup(cleanup) {
|
|
52
|
+
if (disposed) {
|
|
53
|
+
cleanup();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
cleanups.push(cleanup);
|
|
57
|
+
},
|
|
58
|
+
onDispose(cleanup) {
|
|
59
|
+
owner.addCleanup(cleanup);
|
|
60
|
+
},
|
|
61
|
+
onError(handler) {
|
|
62
|
+
errorHandlers.add(handler);
|
|
63
|
+
const remove = /* @__PURE__ */ __name(() => errorHandlers.delete(handler), "remove");
|
|
64
|
+
owner.addCleanup(remove);
|
|
65
|
+
return remove;
|
|
66
|
+
},
|
|
67
|
+
handleError(error) {
|
|
68
|
+
for (const handler of [...errorHandlers].reverse()) {
|
|
69
|
+
try {
|
|
70
|
+
handler(error);
|
|
71
|
+
return true;
|
|
72
|
+
} catch (handlerError) {
|
|
73
|
+
return parent?.handleError(handlerError) ?? false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return parent?.handleError(error) ?? false;
|
|
77
|
+
},
|
|
78
|
+
dispose() {
|
|
79
|
+
if (disposed) return;
|
|
80
|
+
disposed = true;
|
|
81
|
+
for (const child of [...children]) child.dispose();
|
|
82
|
+
children.length = 0;
|
|
83
|
+
let firstError;
|
|
84
|
+
for (let index = cleanups.length - 1; index >= 0; index--) {
|
|
85
|
+
try {
|
|
86
|
+
cleanups[index]();
|
|
87
|
+
} catch (error) {
|
|
88
|
+
firstError ?? (firstError = error);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
cleanups.length = 0;
|
|
92
|
+
if (parent) {
|
|
93
|
+
const index = parent.children.indexOf(owner);
|
|
94
|
+
if (index >= 0) parent.children.splice(index, 1);
|
|
95
|
+
}
|
|
96
|
+
if (firstError) throw firstError;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
if (parent && !parent.disposed) parent.children.push(owner);
|
|
100
|
+
return owner;
|
|
101
|
+
}
|
|
102
|
+
__name(createOwner, "createOwner");
|
|
103
|
+
function setOwnerDebugName(owner, name) {
|
|
104
|
+
ownerNames.set(owner, name);
|
|
105
|
+
}
|
|
106
|
+
__name(setOwnerDebugName, "setOwnerDebugName");
|
|
107
|
+
function getCurrentOwner() {
|
|
108
|
+
return currentOwner;
|
|
109
|
+
}
|
|
110
|
+
__name(getCurrentOwner, "getCurrentOwner");
|
|
111
|
+
function onDispose(cleanup) {
|
|
112
|
+
const owner = getCurrentOwner();
|
|
113
|
+
if (!owner) throw new Error("Vobs: onDispose \u5FC5\u987B\u5728 Owner \u4F5C\u7528\u57DF\u5185\u8C03\u7528");
|
|
114
|
+
owner.onDispose(cleanup);
|
|
115
|
+
}
|
|
116
|
+
__name(onDispose, "onDispose");
|
|
117
|
+
|
|
118
|
+
// packages/reactivity/src/signal.ts
|
|
119
|
+
var currentSubscriber = null;
|
|
120
|
+
function getCurrentSubscriber() {
|
|
121
|
+
return currentSubscriber;
|
|
122
|
+
}
|
|
123
|
+
__name(getCurrentSubscriber, "getCurrentSubscriber");
|
|
124
|
+
function setCurrentSubscriber(subscriber) {
|
|
125
|
+
currentSubscriber = subscriber;
|
|
126
|
+
}
|
|
127
|
+
__name(setCurrentSubscriber, "setCurrentSubscriber");
|
|
128
|
+
function trackDependency(dependency) {
|
|
129
|
+
if (!currentSubscriber || currentSubscriber.disposed) return;
|
|
130
|
+
!currentSubscriber.dependencies.has(dependency);
|
|
131
|
+
currentSubscriber.dependencies.add(dependency);
|
|
132
|
+
}
|
|
133
|
+
__name(trackDependency, "trackDependency");
|
|
134
|
+
function state(initialValue, debugName) {
|
|
135
|
+
let value = initialValue;
|
|
136
|
+
let disposed = false;
|
|
137
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
138
|
+
const signalInstance = {
|
|
139
|
+
get value() {
|
|
140
|
+
const subscriber = getCurrentSubscriber();
|
|
141
|
+
if (subscriber && !subscriber.disposed) {
|
|
142
|
+
subscribers.add(subscriber);
|
|
143
|
+
trackDependency(signalInstance);
|
|
144
|
+
}
|
|
145
|
+
return value;
|
|
146
|
+
},
|
|
147
|
+
set value(nextValue) {
|
|
148
|
+
if (disposed || Object.is(value, nextValue)) return;
|
|
149
|
+
value = nextValue;
|
|
150
|
+
for (const subscriber of [...subscribers]) subscriber.notify();
|
|
151
|
+
},
|
|
152
|
+
unsubscribe(subscriber) {
|
|
153
|
+
subscribers.delete(subscriber);
|
|
154
|
+
},
|
|
155
|
+
// 与 `.value =` 赋值同一条路径:判等短路、debug hook、notify 全部一致。
|
|
156
|
+
// 以闭包实现,可安全地作为回调直接传递(无 this 绑定问题)。
|
|
157
|
+
set(next) {
|
|
158
|
+
signalInstance.value = next;
|
|
159
|
+
},
|
|
160
|
+
dispose() {
|
|
161
|
+
if (disposed) return;
|
|
162
|
+
disposed = true;
|
|
163
|
+
subscribers.clear();
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
const owner = getCurrentOwner();
|
|
167
|
+
owner?.addCleanup(signalInstance.dispose);
|
|
168
|
+
if (debugName?.trim()) setSignalDebugName(signalInstance, debugName.trim());
|
|
169
|
+
return signalInstance;
|
|
170
|
+
}
|
|
171
|
+
__name(state, "state");
|
|
172
|
+
|
|
173
|
+
// packages/reactivity/src/scheduler.ts
|
|
174
|
+
var _Scheduler = class _Scheduler {
|
|
175
|
+
constructor() {
|
|
176
|
+
this.dirtyEffects = /* @__PURE__ */ new Set();
|
|
177
|
+
this.lowPriorityEffects = /* @__PURE__ */ new Set();
|
|
178
|
+
// flush 不可重入(flushing 标志保证),缓冲数组可在轮次间安全复用,避免每轮分配。
|
|
179
|
+
this.normalBuffer = [];
|
|
180
|
+
this.lowBuffer = [];
|
|
181
|
+
this.flushing = false;
|
|
182
|
+
this.scheduled = false;
|
|
183
|
+
this.batchDepth = 0;
|
|
184
|
+
}
|
|
185
|
+
schedule(effect2) {
|
|
186
|
+
if (effect2.disposed) return;
|
|
187
|
+
this.dirtyEffects.add(effect2);
|
|
188
|
+
this.lowPriorityEffects.delete(effect2);
|
|
189
|
+
this.ensureScheduled();
|
|
190
|
+
}
|
|
191
|
+
/** Queue an effect behind normal updates while preserving deterministic order. */
|
|
192
|
+
scheduleLow(effect2) {
|
|
193
|
+
if (effect2.disposed) return;
|
|
194
|
+
if (!this.dirtyEffects.has(effect2)) this.lowPriorityEffects.add(effect2);
|
|
195
|
+
this.ensureScheduled();
|
|
196
|
+
}
|
|
197
|
+
ensureScheduled() {
|
|
198
|
+
if (this.batchDepth === 0 && !this.flushing && !this.scheduled) {
|
|
199
|
+
this.scheduled = true;
|
|
200
|
+
queueMicrotask(() => {
|
|
201
|
+
this.scheduled = false;
|
|
202
|
+
this.flush();
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
remove(effect2) {
|
|
207
|
+
this.dirtyEffects.delete(effect2);
|
|
208
|
+
this.lowPriorityEffects.delete(effect2);
|
|
209
|
+
}
|
|
210
|
+
batch(fn) {
|
|
211
|
+
this.batchDepth++;
|
|
212
|
+
try {
|
|
213
|
+
return fn();
|
|
214
|
+
} finally {
|
|
215
|
+
this.batchDepth--;
|
|
216
|
+
if (this.batchDepth === 0) this.flush();
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
flush() {
|
|
220
|
+
if (this.flushing || this.batchDepth > 0) return;
|
|
221
|
+
this.flushing = true;
|
|
222
|
+
let rounds = 0;
|
|
223
|
+
let firstError;
|
|
224
|
+
let hasError = false;
|
|
225
|
+
try {
|
|
226
|
+
while (this.dirtyEffects.size > 0 || this.lowPriorityEffects.size > 0) {
|
|
227
|
+
if (++rounds > 100) {
|
|
228
|
+
this.dirtyEffects.clear();
|
|
229
|
+
this.lowPriorityEffects.clear();
|
|
230
|
+
throw new Error("Vobs: \u54CD\u5E94\u5F0F\u66F4\u65B0\u8D85\u8FC7 100 \u8F6E\uFF0C\u53EF\u80FD\u5B58\u5728\u5FAA\u73AF\u4F9D\u8D56");
|
|
231
|
+
}
|
|
232
|
+
this.collectRunnable(this.dirtyEffects, this.normalBuffer);
|
|
233
|
+
this.collectRunnable(this.lowPriorityEffects, this.lowBuffer);
|
|
234
|
+
sortEffects(this.normalBuffer);
|
|
235
|
+
sortEffects(this.lowBuffer);
|
|
236
|
+
for (const effect2 of this.normalBuffer) {
|
|
237
|
+
try {
|
|
238
|
+
effect2.run();
|
|
239
|
+
} catch (error) {
|
|
240
|
+
if (!hasError) {
|
|
241
|
+
firstError = error;
|
|
242
|
+
hasError = true;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
for (const effect2 of this.lowBuffer) {
|
|
247
|
+
try {
|
|
248
|
+
effect2.run();
|
|
249
|
+
} catch (error) {
|
|
250
|
+
if (!hasError) {
|
|
251
|
+
firstError = error;
|
|
252
|
+
hasError = true;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
this.normalBuffer.length = 0;
|
|
257
|
+
this.lowBuffer.length = 0;
|
|
258
|
+
}
|
|
259
|
+
} finally {
|
|
260
|
+
this.normalBuffer.length = 0;
|
|
261
|
+
this.lowBuffer.length = 0;
|
|
262
|
+
this.flushing = false;
|
|
263
|
+
}
|
|
264
|
+
if (hasError) throw firstError;
|
|
265
|
+
}
|
|
266
|
+
/** 收集未 disposed 的 effect 并清空源集合;run() 期间新调度的 effect 留给下一轮。 */
|
|
267
|
+
collectRunnable(source, target) {
|
|
268
|
+
for (const effect2 of source) {
|
|
269
|
+
if (!effect2.disposed) target.push(effect2);
|
|
270
|
+
}
|
|
271
|
+
source.clear();
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
__name(_Scheduler, "Scheduler");
|
|
275
|
+
var Scheduler = _Scheduler;
|
|
276
|
+
function sortEffects(effects) {
|
|
277
|
+
if (effects.length > 1) {
|
|
278
|
+
effects.sort((a, b) => b.depth - a.depth || a.order - b.order);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
__name(sortEffects, "sortEffects");
|
|
282
|
+
var scheduler = new Scheduler();
|
|
283
|
+
|
|
284
|
+
// packages/reactivity/src/effect.ts
|
|
285
|
+
var nextEffectOrder = 1;
|
|
286
|
+
function cleanupDependencies(subscriber) {
|
|
287
|
+
for (const dependency of subscriber.dependencies) {
|
|
288
|
+
dependency.unsubscribe(subscriber);
|
|
289
|
+
}
|
|
290
|
+
subscriber.dependencies.clear();
|
|
291
|
+
}
|
|
292
|
+
__name(cleanupDependencies, "cleanupDependencies");
|
|
293
|
+
function effect(callback) {
|
|
294
|
+
const owner = getCurrentOwner();
|
|
295
|
+
let cleanup;
|
|
296
|
+
let dirty = true;
|
|
297
|
+
let disposed = false;
|
|
298
|
+
const eff = {
|
|
299
|
+
order: nextEffectOrder++,
|
|
300
|
+
depth: owner?.depth ?? 0,
|
|
301
|
+
dependencies: /* @__PURE__ */ new Set(),
|
|
302
|
+
get disposed() {
|
|
303
|
+
return disposed;
|
|
304
|
+
},
|
|
305
|
+
notify() {
|
|
306
|
+
if (disposed || dirty) return;
|
|
307
|
+
dirty = true;
|
|
308
|
+
scheduler.schedule(eff);
|
|
309
|
+
},
|
|
310
|
+
run() {
|
|
311
|
+
if (disposed || !dirty) return;
|
|
312
|
+
dirty = false;
|
|
313
|
+
const previousCleanup = cleanup;
|
|
314
|
+
cleanup = void 0;
|
|
315
|
+
let cleanupError;
|
|
316
|
+
if (previousCleanup) {
|
|
317
|
+
try {
|
|
318
|
+
previousCleanup();
|
|
319
|
+
} catch (error) {
|
|
320
|
+
const handled2 = owner?.handleError(error) ?? false;
|
|
321
|
+
if (!handled2) cleanupError = error;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
cleanupDependencies(eff);
|
|
325
|
+
const previous = getCurrentSubscriber();
|
|
326
|
+
setCurrentSubscriber(eff);
|
|
327
|
+
let thrown;
|
|
328
|
+
let handled = false;
|
|
329
|
+
try {
|
|
330
|
+
const result = owner ? owner.run(callback) : callback();
|
|
331
|
+
cleanup = typeof result === "function" ? result : void 0;
|
|
332
|
+
} catch (error) {
|
|
333
|
+
thrown = error;
|
|
334
|
+
handled = owner?.handleError(error) ?? false;
|
|
335
|
+
if (!handled) throw error;
|
|
336
|
+
} finally {
|
|
337
|
+
setCurrentSubscriber(previous);
|
|
338
|
+
}
|
|
339
|
+
if (cleanupError && !thrown) throw cleanupError;
|
|
340
|
+
},
|
|
341
|
+
scheduleLow() {
|
|
342
|
+
if (disposed || dirty) return;
|
|
343
|
+
dirty = true;
|
|
344
|
+
scheduler.scheduleLow(eff);
|
|
345
|
+
},
|
|
346
|
+
dispose() {
|
|
347
|
+
if (disposed) return;
|
|
348
|
+
disposed = true;
|
|
349
|
+
dirty = false;
|
|
350
|
+
scheduler.remove(eff);
|
|
351
|
+
const previousCleanup = cleanup;
|
|
352
|
+
cleanup = void 0;
|
|
353
|
+
let cleanupError;
|
|
354
|
+
if (previousCleanup) {
|
|
355
|
+
try {
|
|
356
|
+
previousCleanup();
|
|
357
|
+
} catch (error) {
|
|
358
|
+
const handled = owner?.handleError(error) ?? false;
|
|
359
|
+
if (!handled) cleanupError = error;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
cleanupDependencies(eff);
|
|
363
|
+
if (cleanupError) throw cleanupError;
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
owner?.addCleanup(eff.dispose);
|
|
367
|
+
eff.run();
|
|
368
|
+
return eff;
|
|
369
|
+
}
|
|
370
|
+
__name(effect, "effect");
|
|
371
|
+
|
|
372
|
+
// packages/runtime/src/debug.ts
|
|
373
|
+
var activeRuntimeDebugHooks = null;
|
|
374
|
+
function getRuntimeDebugHooks() {
|
|
375
|
+
return activeRuntimeDebugHooks;
|
|
376
|
+
}
|
|
377
|
+
__name(getRuntimeDebugHooks, "getRuntimeDebugHooks");
|
|
378
|
+
function invokeRuntimeDebug(name, ...args) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
__name(invokeRuntimeDebug, "invokeRuntimeDebug");
|
|
382
|
+
function readDebugValue(read) {
|
|
383
|
+
try {
|
|
384
|
+
return read();
|
|
385
|
+
} catch {
|
|
386
|
+
return "[Uninspectable]";
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
__name(readDebugValue, "readDebugValue");
|
|
390
|
+
function describeDebugNode(node) {
|
|
391
|
+
if (!node || typeof node !== "object") return "node";
|
|
392
|
+
const value = node;
|
|
393
|
+
const name = typeof value.tagName === "string" ? value.tagName.toLowerCase() : typeof value.nodeName === "string" ? value.nodeName.toLowerCase() : "node";
|
|
394
|
+
const id = typeof value.id === "string" && value.id ? `#${value.id}` : "";
|
|
395
|
+
const className = typeof value.className === "string" && value.className ? `.${value.className.trim().split(/\s+/).filter(Boolean).join(".")}` : "";
|
|
396
|
+
return `${name}${id}${className}`;
|
|
397
|
+
}
|
|
398
|
+
__name(describeDebugNode, "describeDebugNode");
|
|
399
|
+
|
|
400
|
+
// packages/runtime/src/hmr.ts
|
|
401
|
+
var globalTarget = globalThis;
|
|
402
|
+
var hmrGlobal = globalTarget.__VOBS_HMR__ ?? { modules: /* @__PURE__ */ new Map() };
|
|
403
|
+
globalTarget.__VOBS_HMR__ = hmrGlobal;
|
|
404
|
+
function registerHmrInstance(moduleId, instance) {
|
|
405
|
+
const instances = getModule(moduleId).instances;
|
|
406
|
+
instances.add(instance);
|
|
407
|
+
return () => instances.delete(instance);
|
|
408
|
+
}
|
|
409
|
+
__name(registerHmrInstance, "registerHmrInstance");
|
|
410
|
+
function markHmrInstanceMounted(node, parent) {
|
|
411
|
+
const instance = hmrInstances.get(node);
|
|
412
|
+
if (instance) instance.parent = parent;
|
|
413
|
+
}
|
|
414
|
+
__name(markHmrInstanceMounted, "markHmrInstanceMounted");
|
|
415
|
+
function getModule(moduleId) {
|
|
416
|
+
let module = hmrGlobal.modules.get(moduleId);
|
|
417
|
+
if (!module) {
|
|
418
|
+
module = { components: /* @__PURE__ */ new Map(), state: /* @__PURE__ */ new Map(), instances: /* @__PURE__ */ new Set() };
|
|
419
|
+
hmrGlobal.modules.set(moduleId, module);
|
|
420
|
+
}
|
|
421
|
+
return module;
|
|
422
|
+
}
|
|
423
|
+
__name(getModule, "getModule");
|
|
424
|
+
var hmrInstances = /* @__PURE__ */ new WeakMap();
|
|
425
|
+
function associateHmrInstance(node, instance) {
|
|
426
|
+
hmrInstances.set(node, instance);
|
|
427
|
+
}
|
|
428
|
+
__name(associateHmrInstance, "associateHmrInstance");
|
|
429
|
+
var nodeOwners = /* @__PURE__ */ new WeakMap();
|
|
430
|
+
var eventBindings = /* @__PURE__ */ new WeakMap();
|
|
431
|
+
function getRenderer() {
|
|
432
|
+
{
|
|
433
|
+
throw new Error("\u6E32\u67D3\u5668\u672A\u521D\u59CB\u5316");
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
__name(getRenderer, "getRenderer");
|
|
437
|
+
function createText(content) {
|
|
438
|
+
return getRenderer().createText(content);
|
|
439
|
+
}
|
|
440
|
+
__name(createText, "createText");
|
|
441
|
+
function createElement(tag) {
|
|
442
|
+
return getRenderer().createElement(tag);
|
|
443
|
+
}
|
|
444
|
+
__name(createElement, "createElement");
|
|
445
|
+
function createComment(content) {
|
|
446
|
+
return getRenderer().createComment(content);
|
|
447
|
+
}
|
|
448
|
+
__name(createComment, "createComment");
|
|
449
|
+
function insertBefore(parent, child, anchor) {
|
|
450
|
+
if (isVobsFragment(child)) {
|
|
451
|
+
child.mount(parent, isVobsFragment(anchor) ? anchor.start : anchor);
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
getRenderer().insertBefore(parent, child, isVobsFragment(anchor) ? anchor.start : anchor);
|
|
455
|
+
markHmrInstanceMounted(child, parent);
|
|
456
|
+
}
|
|
457
|
+
__name(insertBefore, "insertBefore");
|
|
458
|
+
function removeChild(parent, child) {
|
|
459
|
+
disposeNodeOwner(child);
|
|
460
|
+
if (isVobsFragment(child)) {
|
|
461
|
+
child.unmount(parent);
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
getRenderer().removeChild(parent, child);
|
|
465
|
+
}
|
|
466
|
+
__name(removeChild, "removeChild");
|
|
467
|
+
function setTextContent(node, content) {
|
|
468
|
+
getRenderer().setTextContent(node, content);
|
|
469
|
+
}
|
|
470
|
+
__name(setTextContent, "setTextContent");
|
|
471
|
+
function setProperty(node, key, value) {
|
|
472
|
+
getRenderer().setProperty(node, key, value);
|
|
473
|
+
}
|
|
474
|
+
__name(setProperty, "setProperty");
|
|
475
|
+
function setAttribute(node, key, value) {
|
|
476
|
+
getRenderer().setAttribute(node, key, value);
|
|
477
|
+
}
|
|
478
|
+
__name(setAttribute, "setAttribute");
|
|
479
|
+
function addEventListener(node, event, handler) {
|
|
480
|
+
const renderer = getRenderer();
|
|
481
|
+
const owner = getCurrentOwner();
|
|
482
|
+
let bindings = eventBindings.get(node);
|
|
483
|
+
if (!bindings) {
|
|
484
|
+
bindings = /* @__PURE__ */ new Map();
|
|
485
|
+
eventBindings.set(node, bindings);
|
|
486
|
+
}
|
|
487
|
+
const previous = bindings.get(event);
|
|
488
|
+
if (previous && previous.original === handler && previous.owner === owner) return;
|
|
489
|
+
if (previous) renderer.removeEventListener(node, event, previous.handler);
|
|
490
|
+
const listener = owner ? (reason) => {
|
|
491
|
+
try {
|
|
492
|
+
owner.run(() => handler(reason));
|
|
493
|
+
} catch (error) {
|
|
494
|
+
const handled = owner.handleError(error);
|
|
495
|
+
invokeRuntimeDebug("error", {
|
|
496
|
+
error,
|
|
497
|
+
owner,
|
|
498
|
+
phase: "event",
|
|
499
|
+
handled,
|
|
500
|
+
recovery: handled ? "handled" : "propagated"
|
|
501
|
+
});
|
|
502
|
+
if (!handled) throw error;
|
|
503
|
+
}
|
|
504
|
+
} : handler;
|
|
505
|
+
const binding = { handler: listener, owner, original: handler };
|
|
506
|
+
bindings.set(event, binding);
|
|
507
|
+
renderer.addEventListener(node, event, listener);
|
|
508
|
+
owner?.onDispose(() => {
|
|
509
|
+
if (bindings?.get(event) !== binding) return;
|
|
510
|
+
bindings.delete(event);
|
|
511
|
+
renderer.removeEventListener(node, event, listener);
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
__name(addEventListener, "addEventListener");
|
|
515
|
+
function createComponent(component, props, source) {
|
|
516
|
+
const owner = createOwner();
|
|
517
|
+
const componentName = component.displayName || component.name || "anonymous";
|
|
518
|
+
setOwnerDebugName(owner, source ? `${componentName} (${source.file}:${source.line}:${source.column})` : componentName);
|
|
519
|
+
owner.onError((reason) => {
|
|
520
|
+
attachSourceLocation(reason, source);
|
|
521
|
+
attachComponentContext(reason, componentName, owner.id);
|
|
522
|
+
throw reason;
|
|
523
|
+
});
|
|
524
|
+
let node;
|
|
525
|
+
try {
|
|
526
|
+
node = owner.run(() => component(props));
|
|
527
|
+
} catch (error) {
|
|
528
|
+
owner.dispose();
|
|
529
|
+
attachSourceLocation(error, source);
|
|
530
|
+
attachComponentContext(error, componentName, owner.id);
|
|
531
|
+
throw error;
|
|
532
|
+
}
|
|
533
|
+
associateNodeOwner(node, owner);
|
|
534
|
+
const hmrKey = component.hmrKey;
|
|
535
|
+
if (hmrKey) {
|
|
536
|
+
const instance = {
|
|
537
|
+
node,
|
|
538
|
+
parent: null,
|
|
539
|
+
refresh() {
|
|
540
|
+
const previous = instance.node;
|
|
541
|
+
const next = owner.run(() => component(props));
|
|
542
|
+
if (instance.parent && !isVobsFragment(previous) && !isVobsFragment(next)) {
|
|
543
|
+
getRenderer().insertBefore(instance.parent, next, previous);
|
|
544
|
+
getRenderer().removeChild(instance.parent, previous);
|
|
545
|
+
}
|
|
546
|
+
nodeOwners.delete(previous);
|
|
547
|
+
nodeOwners.set(next, owner);
|
|
548
|
+
associateHmrInstance(next, instance);
|
|
549
|
+
instance.node = next;
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
associateHmrInstance(node, instance);
|
|
553
|
+
const separator = hmrKey.lastIndexOf(":");
|
|
554
|
+
const moduleId = separator < 0 ? hmrKey : hmrKey.slice(0, separator);
|
|
555
|
+
const cleanup = registerHmrInstance(moduleId, instance);
|
|
556
|
+
owner.onDispose(cleanup);
|
|
557
|
+
}
|
|
558
|
+
return node;
|
|
559
|
+
}
|
|
560
|
+
__name(createComponent, "createComponent");
|
|
561
|
+
function attachSourceLocation(reason, source) {
|
|
562
|
+
if (!source || (!reason || typeof reason !== "object" && typeof reason !== "function")) return;
|
|
563
|
+
const error = reason;
|
|
564
|
+
if (error.vobsSource) return;
|
|
565
|
+
try {
|
|
566
|
+
Object.defineProperty(error, "vobsSource", {
|
|
567
|
+
configurable: true,
|
|
568
|
+
enumerable: false,
|
|
569
|
+
value: source,
|
|
570
|
+
writable: false
|
|
571
|
+
});
|
|
572
|
+
} catch {
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
__name(attachSourceLocation, "attachSourceLocation");
|
|
576
|
+
function attachComponentContext(reason, component, ownerId) {
|
|
577
|
+
if (!reason || typeof reason !== "object" && typeof reason !== "function") return;
|
|
578
|
+
const error = reason;
|
|
579
|
+
try {
|
|
580
|
+
if (!error.vobsComponent) Object.defineProperty(error, "vobsComponent", { configurable: true, enumerable: false, value: component, writable: false });
|
|
581
|
+
if (!error.vobsOwnerId) Object.defineProperty(error, "vobsOwnerId", { configurable: true, enumerable: false, value: ownerId, writable: false });
|
|
582
|
+
} catch {
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
__name(attachComponentContext, "attachComponentContext");
|
|
586
|
+
function createBlock(factory) {
|
|
587
|
+
const owner = createOwner();
|
|
588
|
+
setOwnerDebugName(owner, "dynamic");
|
|
589
|
+
let node;
|
|
590
|
+
try {
|
|
591
|
+
node = owner.run(factory);
|
|
592
|
+
} catch (error) {
|
|
593
|
+
owner.dispose();
|
|
594
|
+
throw error;
|
|
595
|
+
}
|
|
596
|
+
if (!node) {
|
|
597
|
+
owner.dispose();
|
|
598
|
+
return null;
|
|
599
|
+
}
|
|
600
|
+
associateNodeOwner(node, owner);
|
|
601
|
+
return node;
|
|
602
|
+
}
|
|
603
|
+
__name(createBlock, "createBlock");
|
|
604
|
+
function associateNodeOwner(node, owner) {
|
|
605
|
+
nodeOwners.set(node, owner);
|
|
606
|
+
}
|
|
607
|
+
__name(associateNodeOwner, "associateNodeOwner");
|
|
608
|
+
function disposeNodeOwner(node) {
|
|
609
|
+
const owner = nodeOwners.get(node);
|
|
610
|
+
if (!owner) return;
|
|
611
|
+
nodeOwners.delete(node);
|
|
612
|
+
owner.dispose();
|
|
613
|
+
}
|
|
614
|
+
__name(disposeNodeOwner, "disposeNodeOwner");
|
|
615
|
+
|
|
616
|
+
// packages/runtime/src/fragment.ts
|
|
617
|
+
function createFragment(factory) {
|
|
618
|
+
const start = createComment("vobs:fragment:start");
|
|
619
|
+
const end = createComment("vobs:fragment:end");
|
|
620
|
+
let parent = null;
|
|
621
|
+
let initialized = false;
|
|
622
|
+
const owner = getCurrentOwner();
|
|
623
|
+
const fragment = {
|
|
624
|
+
kind: "vobs-fragment",
|
|
625
|
+
start,
|
|
626
|
+
end,
|
|
627
|
+
mount(nextParent, anchor) {
|
|
628
|
+
if (parent && parent !== nextParent) {
|
|
629
|
+
throw new Error("Vobs Fragment: \u4E0D\u80FD\u8DE8\u7236\u8282\u70B9\u79FB\u52A8 Fragment");
|
|
630
|
+
}
|
|
631
|
+
if (initialized) {
|
|
632
|
+
moveRange(nextParent, start, end, anchor);
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
const renderer = getRenderer();
|
|
636
|
+
renderer.insertBefore(nextParent, start, anchor);
|
|
637
|
+
renderer.insertBefore(nextParent, end, anchor);
|
|
638
|
+
parent = nextParent;
|
|
639
|
+
initialized = true;
|
|
640
|
+
if (owner) owner.run(() => factory(nextParent, end));
|
|
641
|
+
else factory(nextParent, end);
|
|
642
|
+
},
|
|
643
|
+
unmount(nextParent) {
|
|
644
|
+
if (!initialized || parent !== nextParent) {
|
|
645
|
+
throw new Error("Vobs Fragment: Fragment \u4E0D\u5C5E\u4E8E\u6307\u5B9A\u7236\u8282\u70B9");
|
|
646
|
+
}
|
|
647
|
+
const renderer = getRenderer();
|
|
648
|
+
let current = renderer.nextSibling(start);
|
|
649
|
+
while (current && current !== end) {
|
|
650
|
+
const next = renderer.nextSibling(current);
|
|
651
|
+
renderer.removeChild(nextParent, current);
|
|
652
|
+
current = next;
|
|
653
|
+
}
|
|
654
|
+
renderer.removeChild(nextParent, start);
|
|
655
|
+
renderer.removeChild(nextParent, end);
|
|
656
|
+
parent = null;
|
|
657
|
+
initialized = false;
|
|
658
|
+
}
|
|
659
|
+
};
|
|
660
|
+
return fragment;
|
|
661
|
+
}
|
|
662
|
+
__name(createFragment, "createFragment");
|
|
663
|
+
function isVobsFragment(value) {
|
|
664
|
+
return Boolean(value) && typeof value === "object" && value.kind === "vobs-fragment";
|
|
665
|
+
}
|
|
666
|
+
__name(isVobsFragment, "isVobsFragment");
|
|
667
|
+
function moveRange(parent, start, end, anchor) {
|
|
668
|
+
const renderer = getRenderer();
|
|
669
|
+
const nodes = [start];
|
|
670
|
+
let current = renderer.nextSibling(start);
|
|
671
|
+
while (current) {
|
|
672
|
+
nodes.push(current);
|
|
673
|
+
if (current === end) break;
|
|
674
|
+
current = renderer.nextSibling(current);
|
|
675
|
+
}
|
|
676
|
+
if (nodes[nodes.length - 1] !== end) {
|
|
677
|
+
throw new Error("Vobs Fragment: \u627E\u4E0D\u5230\u7ED3\u675F\u951A\u70B9");
|
|
678
|
+
}
|
|
679
|
+
for (const node of nodes) renderer.insertBefore(parent, node, anchor);
|
|
680
|
+
}
|
|
681
|
+
__name(moveRange, "moveRange");
|
|
682
|
+
|
|
683
|
+
// packages/runtime/src/dynamic.ts
|
|
684
|
+
function insertDynamic(parent, anchor, factory) {
|
|
685
|
+
const marker = createComment("vobs:dynamic");
|
|
686
|
+
insertBefore(parent, marker, anchor);
|
|
687
|
+
let current = null;
|
|
688
|
+
effect(() => {
|
|
689
|
+
const next = createBlock(factory);
|
|
690
|
+
if (next === current) return;
|
|
691
|
+
if (current) removeChild(parent, current);
|
|
692
|
+
current = next;
|
|
693
|
+
if (current) insertBefore(parent, current, marker);
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
__name(insertDynamic, "insertDynamic");
|
|
697
|
+
|
|
698
|
+
// packages/vobs/src/context.ts
|
|
699
|
+
var ownerProviders = /* @__PURE__ */ new WeakMap();
|
|
700
|
+
function inject(key, fallback) {
|
|
701
|
+
const owner = getCurrentOwner();
|
|
702
|
+
const value = owner ? injectFromOwner(owner, key) : void 0;
|
|
703
|
+
return value === void 0 ? fallback : value;
|
|
704
|
+
}
|
|
705
|
+
__name(inject, "inject");
|
|
706
|
+
function injectFromOwner(owner, key) {
|
|
707
|
+
let current = owner;
|
|
708
|
+
while (current) {
|
|
709
|
+
const providers = ownerProviders.get(current);
|
|
710
|
+
if (providers?.has(key)) return providers.get(key);
|
|
711
|
+
current = current.parent;
|
|
712
|
+
}
|
|
713
|
+
return void 0;
|
|
714
|
+
}
|
|
715
|
+
__name(injectFromOwner, "injectFromOwner");
|
|
716
|
+
|
|
717
|
+
// packages/vobs/src/app.ts
|
|
718
|
+
function createInjectionKey(description) {
|
|
719
|
+
return Symbol(description);
|
|
720
|
+
}
|
|
721
|
+
__name(createInjectionKey, "createInjectionKey");
|
|
722
|
+
var HTTP_KEY = createInjectionKey("vobs.http");
|
|
723
|
+
var activeDevTools = null;
|
|
724
|
+
function getDevTools() {
|
|
725
|
+
return activeDevTools;
|
|
726
|
+
}
|
|
727
|
+
__name(getDevTools, "getDevTools");
|
|
728
|
+
|
|
729
|
+
// packages/ui/src/utils.ts
|
|
730
|
+
function classNames(...values) {
|
|
731
|
+
return values.flatMap((value) => typeof value === "string" ? value.trim().split(/\s+/u) : []).filter(Boolean).join(" ");
|
|
732
|
+
}
|
|
733
|
+
__name(classNames, "classNames");
|
|
734
|
+
function readProp(props, name, fallback) {
|
|
735
|
+
const value = Reflect.get(props, name);
|
|
736
|
+
return value === void 0 ? fallback : value;
|
|
737
|
+
}
|
|
738
|
+
__name(readProp, "readProp");
|
|
739
|
+
function hasProp(props, name) {
|
|
740
|
+
return name in props;
|
|
741
|
+
}
|
|
742
|
+
__name(hasProp, "hasProp");
|
|
743
|
+
function bindClassList(root, props, readBaseClasses) {
|
|
744
|
+
effect(() => {
|
|
745
|
+
setAttribute(root, "class", classNames(
|
|
746
|
+
...readBaseClasses(),
|
|
747
|
+
readString(props, "class"),
|
|
748
|
+
readString(props, "className")
|
|
749
|
+
));
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
__name(bindClassList, "bindClassList");
|
|
753
|
+
function bindCommonAttributes(root, props, skip = [], options = {}) {
|
|
754
|
+
const ignored = new Set(skip);
|
|
755
|
+
ignored.add("class");
|
|
756
|
+
ignored.add("className");
|
|
757
|
+
ignored.add("children");
|
|
758
|
+
ignored.add("style");
|
|
759
|
+
effect(() => {
|
|
760
|
+
const next = /* @__PURE__ */ new Map();
|
|
761
|
+
for (const name of Object.keys(props)) {
|
|
762
|
+
if (ignored.has(name) || name.startsWith("on")) continue;
|
|
763
|
+
if (!isCommonAttribute(name)) continue;
|
|
764
|
+
if (options.includeDataAria === false && (name.startsWith("aria-") || name.startsWith("data-"))) continue;
|
|
765
|
+
const value = Reflect.get(props, name);
|
|
766
|
+
const normalized = normalizeAttribute(name, value);
|
|
767
|
+
if (normalized !== void 0) next.set(normalized.name, normalized.value);
|
|
768
|
+
}
|
|
769
|
+
const managed = getManagedAttributes(root);
|
|
770
|
+
for (const name of managed) {
|
|
771
|
+
if (!next.has(name)) removeAttribute(root, name);
|
|
772
|
+
}
|
|
773
|
+
for (const [name, value] of next) setAttribute(root, name, value);
|
|
774
|
+
setManagedAttributes(root, next.keys());
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
__name(bindCommonAttributes, "bindCommonAttributes");
|
|
778
|
+
function bindUserStyle(root, props) {
|
|
779
|
+
bindStyle(root, props, () => "");
|
|
780
|
+
}
|
|
781
|
+
__name(bindUserStyle, "bindUserStyle");
|
|
782
|
+
function bindStyle(root, props, createStyle) {
|
|
783
|
+
effect(() => {
|
|
784
|
+
const userStyle = readString(props, "style");
|
|
785
|
+
const internalStyle = createStyle();
|
|
786
|
+
const style = [internalStyle, userStyle].filter(Boolean).join("; ");
|
|
787
|
+
if (style) setAttribute(root, "style", style);
|
|
788
|
+
else removeAttribute(root, "style");
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
__name(bindStyle, "bindStyle");
|
|
792
|
+
function bindTextContent(node, read) {
|
|
793
|
+
effect(() => {
|
|
794
|
+
setTextContent(node, String(read() ?? ""));
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
__name(bindTextContent, "bindTextContent");
|
|
798
|
+
function bindPropertyValue(node, name, read) {
|
|
799
|
+
effect(() => setProperty(node, name, read()));
|
|
800
|
+
}
|
|
801
|
+
__name(bindPropertyValue, "bindPropertyValue");
|
|
802
|
+
function listen(root, event, props, propName, disabled) {
|
|
803
|
+
addEventListener(root, event, (reason) => {
|
|
804
|
+
if (disabled?.()) return;
|
|
805
|
+
const handler = Reflect.get(props, propName);
|
|
806
|
+
if (typeof handler === "function") handler(reason);
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
__name(listen, "listen");
|
|
810
|
+
function mountSlot(parent, props, propName) {
|
|
811
|
+
insertDynamic(parent, null, () => resolveSlot(Reflect.get(props, propName)));
|
|
812
|
+
}
|
|
813
|
+
__name(mountSlot, "mountSlot");
|
|
814
|
+
function resolveSlot(value) {
|
|
815
|
+
const resolved = typeof value === "function" ? value() : value;
|
|
816
|
+
if (resolved === void 0 || resolved === null || resolved === false) return null;
|
|
817
|
+
if (typeof resolved === "string" || typeof resolved === "number") return createText(String(resolved));
|
|
818
|
+
if (Array.isArray(resolved)) {
|
|
819
|
+
const children = resolved;
|
|
820
|
+
return createFragment((parent, anchor) => {
|
|
821
|
+
for (const child of children) {
|
|
822
|
+
const node = resolveSlot(child);
|
|
823
|
+
if (node) insertBefore(parent, node, anchor);
|
|
824
|
+
}
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
return resolved;
|
|
828
|
+
}
|
|
829
|
+
__name(resolveSlot, "resolveSlot");
|
|
830
|
+
function setOptionalAttribute(node, name, value) {
|
|
831
|
+
if (value === void 0 || value === null || value === false || value === "") {
|
|
832
|
+
removeAttribute(node, name);
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
setAttribute(node, name, String(value));
|
|
836
|
+
}
|
|
837
|
+
__name(setOptionalAttribute, "setOptionalAttribute");
|
|
838
|
+
function setOptionalProperty(node, name, value) {
|
|
839
|
+
if (value === void 0 || value === null) return;
|
|
840
|
+
setProperty(node, name, value);
|
|
841
|
+
}
|
|
842
|
+
__name(setOptionalProperty, "setOptionalProperty");
|
|
843
|
+
function readString(props, name) {
|
|
844
|
+
const value = Reflect.get(props, name);
|
|
845
|
+
return typeof value === "string" ? value : void 0;
|
|
846
|
+
}
|
|
847
|
+
__name(readString, "readString");
|
|
848
|
+
function isCommonAttribute(name) {
|
|
849
|
+
return name === "id" || name === "title" || name === "role" || name === "tabIndex" || name.startsWith("aria-") || name.startsWith("data-");
|
|
850
|
+
}
|
|
851
|
+
__name(isCommonAttribute, "isCommonAttribute");
|
|
852
|
+
function normalizeAttribute(name, value) {
|
|
853
|
+
if (value === void 0 || value === null) return void 0;
|
|
854
|
+
if (value === false && !name.startsWith("aria-") && !name.startsWith("data-")) return void 0;
|
|
855
|
+
return { name: name === "tabIndex" ? "tabindex" : name, value: String(value) };
|
|
856
|
+
}
|
|
857
|
+
__name(normalizeAttribute, "normalizeAttribute");
|
|
858
|
+
var managedAttributes = /* @__PURE__ */ new WeakMap();
|
|
859
|
+
function getManagedAttributes(node) {
|
|
860
|
+
return managedAttributes.get(node) ?? /* @__PURE__ */ new Set();
|
|
861
|
+
}
|
|
862
|
+
__name(getManagedAttributes, "getManagedAttributes");
|
|
863
|
+
function setManagedAttributes(node, names) {
|
|
864
|
+
managedAttributes.set(node, new Set(names));
|
|
865
|
+
}
|
|
866
|
+
__name(setManagedAttributes, "setManagedAttributes");
|
|
867
|
+
function removeAttribute(node, name) {
|
|
868
|
+
const candidate = node;
|
|
869
|
+
candidate.removeAttribute?.(name);
|
|
870
|
+
}
|
|
871
|
+
__name(removeAttribute, "removeAttribute");
|
|
872
|
+
|
|
873
|
+
// packages/ui/src/button.ts
|
|
874
|
+
function Button(props = {}) {
|
|
875
|
+
const root = createElement("button");
|
|
876
|
+
bindClassList(root, props, () => [
|
|
877
|
+
"vui-btn",
|
|
878
|
+
`vui-btn--${readProp(props, "variant", "primary")}`,
|
|
879
|
+
`vui-btn--${readProp(props, "size", "md")}`,
|
|
880
|
+
readProp(props, "iconOnly", false) ? "vui-btn--icon" : void 0
|
|
881
|
+
]);
|
|
882
|
+
bindCommonAttributes(root, props, [
|
|
883
|
+
"variant",
|
|
884
|
+
"size",
|
|
885
|
+
"type",
|
|
886
|
+
"disabled",
|
|
887
|
+
"loading",
|
|
888
|
+
"iconOnly",
|
|
889
|
+
"icon",
|
|
890
|
+
"onClick"
|
|
891
|
+
]);
|
|
892
|
+
effect(() => {
|
|
893
|
+
const disabled = readProp(props, "disabled", false) || readProp(props, "loading", false);
|
|
894
|
+
setOptionalProperty(root, "disabled", disabled);
|
|
895
|
+
setOptionalAttribute(root, "type", readProp(props, "type", "button"));
|
|
896
|
+
setOptionalAttribute(root, "aria-disabled", disabled ? "true" : void 0);
|
|
897
|
+
setOptionalAttribute(root, "aria-busy", readProp(props, "loading", false) ? "true" : void 0);
|
|
898
|
+
});
|
|
899
|
+
listen(root, "click", props, "onClick", () => readProp(props, "disabled", false) || readProp(props, "loading", false));
|
|
900
|
+
if (hasProp(props, "icon")) mountSlot(root, props, "icon");
|
|
901
|
+
if (hasProp(props, "children")) mountSlot(root, props, "children");
|
|
902
|
+
return root;
|
|
903
|
+
}
|
|
904
|
+
__name(Button, "Button");
|
|
905
|
+
|
|
906
|
+
// packages/ui/src/forms.ts
|
|
907
|
+
function bindSignalProp(props) {
|
|
908
|
+
const value = readProp(props, "bind", void 0);
|
|
909
|
+
return value && typeof value === "object" && "value" in value ? value : void 0;
|
|
910
|
+
}
|
|
911
|
+
__name(bindSignalProp, "bindSignalProp");
|
|
912
|
+
function Select(props = {}) {
|
|
913
|
+
const root = createElement("select");
|
|
914
|
+
bindClassList(root, props, () => ["vui-select"]);
|
|
915
|
+
bindCommonAttributes(root, props, [
|
|
916
|
+
"name",
|
|
917
|
+
"value",
|
|
918
|
+
"disabled",
|
|
919
|
+
"required",
|
|
920
|
+
"multiple",
|
|
921
|
+
"size",
|
|
922
|
+
"onChange"
|
|
923
|
+
]);
|
|
924
|
+
effect(() => {
|
|
925
|
+
setOptionalAttribute(root, "name", readProp(props, "name", void 0));
|
|
926
|
+
setOptionalProperty(root, "disabled", readProp(props, "disabled", false));
|
|
927
|
+
setOptionalProperty(root, "required", readProp(props, "required", false));
|
|
928
|
+
setOptionalProperty(root, "multiple", readProp(props, "multiple", false));
|
|
929
|
+
setOptionalAttribute(root, "size", readProp(props, "size", void 0));
|
|
930
|
+
});
|
|
931
|
+
if (hasProp(props, "children")) mountSlot(root, props, "children");
|
|
932
|
+
const bind = bindSignalProp(props);
|
|
933
|
+
if (bind) {
|
|
934
|
+
bindPropertyValue(root, "value", () => String(bind.value ?? ""));
|
|
935
|
+
listen(root, "change", { onChange: /* @__PURE__ */ __name((event) => {
|
|
936
|
+
bind.value = event.target.value;
|
|
937
|
+
}, "onChange") }, "onChange", () => readProp(props, "disabled", false));
|
|
938
|
+
} else if (hasProp(props, "value")) {
|
|
939
|
+
bindPropertyValue(root, "value", () => readProp(props, "value", void 0) ?? "");
|
|
940
|
+
}
|
|
941
|
+
listen(root, "change", props, "onChange", () => readProp(props, "disabled", false));
|
|
942
|
+
return root;
|
|
943
|
+
}
|
|
944
|
+
__name(Select, "Select");
|
|
945
|
+
|
|
946
|
+
// packages/ui/src/card.ts
|
|
947
|
+
function Card(props = {}) {
|
|
948
|
+
const root = createElement("div");
|
|
949
|
+
bindClassList(root, props, () => ["vui-card"]);
|
|
950
|
+
bindCommonAttributes(root, props, ["title", "description"]);
|
|
951
|
+
bindUserStyle(root, props);
|
|
952
|
+
if (hasProp(props, "title")) {
|
|
953
|
+
const title = createElement("div");
|
|
954
|
+
const text = createText("");
|
|
955
|
+
setAttribute(title, "class", "vui-card__title");
|
|
956
|
+
bindTextContent(text, () => readProp(props, "title", ""));
|
|
957
|
+
insertBefore(title, text, null);
|
|
958
|
+
insertBefore(root, title, null);
|
|
959
|
+
}
|
|
960
|
+
if (hasProp(props, "description")) {
|
|
961
|
+
const description = createElement("p");
|
|
962
|
+
const text = createText("");
|
|
963
|
+
setAttribute(description, "class", "vui-card__desc");
|
|
964
|
+
bindTextContent(text, () => readProp(props, "description", ""));
|
|
965
|
+
insertBefore(description, text, null);
|
|
966
|
+
insertBefore(root, description, null);
|
|
967
|
+
}
|
|
968
|
+
if (hasProp(props, "children")) mountSlot(root, props, "children");
|
|
969
|
+
return root;
|
|
970
|
+
}
|
|
971
|
+
__name(Card, "Card");
|
|
972
|
+
|
|
973
|
+
// packages/ui/src/tag.ts
|
|
974
|
+
function Tag(props = {}) {
|
|
975
|
+
const root = createElement("span");
|
|
976
|
+
bindClassList(root, props, () => [
|
|
977
|
+
"vui-tag",
|
|
978
|
+
readProp(props, "tone", "default") === "default" ? void 0 : `vui-tag--${readProp(props, "tone", "default")}`
|
|
979
|
+
]);
|
|
980
|
+
bindCommonAttributes(root, props, ["tone"]);
|
|
981
|
+
bindUserStyle(root, props);
|
|
982
|
+
if (hasProp(props, "children")) mountSlot(root, props, "children");
|
|
983
|
+
return root;
|
|
984
|
+
}
|
|
985
|
+
__name(Tag, "Tag");
|
|
986
|
+
|
|
987
|
+
// packages/ui/src/alert.ts
|
|
988
|
+
function Alert(props = {}) {
|
|
989
|
+
const root = createElement("div");
|
|
990
|
+
bindClassList(root, props, () => [
|
|
991
|
+
"vui-alert",
|
|
992
|
+
`vui-alert--${readProp(props, "tone", "info")}`
|
|
993
|
+
]);
|
|
994
|
+
bindCommonAttributes(root, props, ["tone", "title", "description", "icon", "role"]);
|
|
995
|
+
bindUserStyle(root, props);
|
|
996
|
+
setAttribute(root, "role", "alert");
|
|
997
|
+
if (hasProp(props, "icon")) {
|
|
998
|
+
const icon = createElement("span");
|
|
999
|
+
setAttribute(icon, "class", "vui-alert__icon");
|
|
1000
|
+
mountSlot(icon, props, "icon");
|
|
1001
|
+
insertBefore(root, icon, null);
|
|
1002
|
+
}
|
|
1003
|
+
const content = createElement("div");
|
|
1004
|
+
if (hasProp(props, "title")) {
|
|
1005
|
+
const title = createElement("div");
|
|
1006
|
+
const text = createText("");
|
|
1007
|
+
setAttribute(title, "class", "vui-alert__title");
|
|
1008
|
+
bindTextContent(text, () => readProp(props, "title", ""));
|
|
1009
|
+
insertBefore(title, text, null);
|
|
1010
|
+
insertBefore(content, title, null);
|
|
1011
|
+
}
|
|
1012
|
+
if (hasProp(props, "description")) {
|
|
1013
|
+
const description = createElement("div");
|
|
1014
|
+
const text = createText("");
|
|
1015
|
+
setAttribute(description, "class", "vui-alert__desc");
|
|
1016
|
+
bindTextContent(text, () => readProp(props, "description", ""));
|
|
1017
|
+
insertBefore(description, text, null);
|
|
1018
|
+
insertBefore(content, description, null);
|
|
1019
|
+
}
|
|
1020
|
+
if (hasProp(props, "children")) mountSlot(content, props, "children");
|
|
1021
|
+
insertBefore(root, content, null);
|
|
1022
|
+
return root;
|
|
1023
|
+
}
|
|
1024
|
+
__name(Alert, "Alert");
|
|
1025
|
+
|
|
1026
|
+
// packages/ui/src/tabs.ts
|
|
1027
|
+
function Tabs(props) {
|
|
1028
|
+
const root = createElement("div");
|
|
1029
|
+
const tablist = createElement("div");
|
|
1030
|
+
const panel = createElement("div");
|
|
1031
|
+
const internalValue = state(void 0);
|
|
1032
|
+
bindClassList(root, props, () => ["vui-tabs-root"]);
|
|
1033
|
+
bindCommonAttributes(root, props, ["items", "value", "variant", "onChange"]);
|
|
1034
|
+
setAttribute(tablist, "role", "tablist");
|
|
1035
|
+
effect(() => {
|
|
1036
|
+
const variant = readProp(props, "variant", "default");
|
|
1037
|
+
setAttribute(tablist, "class", `vui-tabs${variant === "filled" ? " vui-tabs--filled" : ""}`);
|
|
1038
|
+
});
|
|
1039
|
+
setAttribute(panel, "class", "vui-tabs__panel");
|
|
1040
|
+
insertDynamic(tablist, null, () => createTabButtons(props, internalValue));
|
|
1041
|
+
insertDynamic(panel, null, () => {
|
|
1042
|
+
const item = activeItem(readProp(props, "items", []), activeId(props, internalValue));
|
|
1043
|
+
return item?.content === void 0 ? null : resolveSlot(item.content);
|
|
1044
|
+
});
|
|
1045
|
+
insertBefore(root, tablist, null);
|
|
1046
|
+
insertBefore(root, panel, null);
|
|
1047
|
+
if (hasProp(props, "children")) mountSlot(root, props, "children");
|
|
1048
|
+
return root;
|
|
1049
|
+
}
|
|
1050
|
+
__name(Tabs, "Tabs");
|
|
1051
|
+
function createTabButtons(props, internalValue) {
|
|
1052
|
+
const items = readProp(props, "items", []);
|
|
1053
|
+
const selected = activeId(props, internalValue);
|
|
1054
|
+
return createFragment((parent, anchor) => {
|
|
1055
|
+
for (const item of items) {
|
|
1056
|
+
const button = createElement("button");
|
|
1057
|
+
const isActive = item.id === selected;
|
|
1058
|
+
setAttribute(button, "class", `vui-tab${isActive ? " is-active" : ""}`);
|
|
1059
|
+
setAttribute(button, "role", "tab");
|
|
1060
|
+
setAttribute(button, "type", "button");
|
|
1061
|
+
setAttribute(button, "aria-selected", isActive ? "true" : "false");
|
|
1062
|
+
setAttribute(button, "data-tab-id", item.id);
|
|
1063
|
+
if (item.disabled === true) {
|
|
1064
|
+
setAttribute(button, "aria-disabled", "true");
|
|
1065
|
+
setProperty(button, "disabled", true);
|
|
1066
|
+
}
|
|
1067
|
+
insertBefore(button, createText(item.label), null);
|
|
1068
|
+
addEventListener(button, "click", () => {
|
|
1069
|
+
if (item.disabled === true) return;
|
|
1070
|
+
if (readProp(props, "value", void 0) === void 0) internalValue.value = item.id;
|
|
1071
|
+
const onChange = readProp(props, "onChange", void 0);
|
|
1072
|
+
if (typeof onChange === "function") onChange(item.id);
|
|
1073
|
+
});
|
|
1074
|
+
insertBefore(parent, button, anchor);
|
|
1075
|
+
}
|
|
1076
|
+
});
|
|
1077
|
+
}
|
|
1078
|
+
__name(createTabButtons, "createTabButtons");
|
|
1079
|
+
function activeId(props, internalValue) {
|
|
1080
|
+
const controlled = readProp(props, "value", void 0);
|
|
1081
|
+
if (controlled !== void 0) return controlled;
|
|
1082
|
+
if (internalValue.value !== void 0) return internalValue.value;
|
|
1083
|
+
return readProp(props, "items", []).find((item) => item.disabled !== true)?.id;
|
|
1084
|
+
}
|
|
1085
|
+
__name(activeId, "activeId");
|
|
1086
|
+
function activeItem(items, id) {
|
|
1087
|
+
return items.find((item) => item.id === id);
|
|
1088
|
+
}
|
|
1089
|
+
__name(activeItem, "activeItem");
|
|
1090
|
+
|
|
1091
|
+
// packages/icon-core/src/index.ts
|
|
1092
|
+
function createSvgIconNode(source, props = {}, options = {}) {
|
|
1093
|
+
const root = createElement("span");
|
|
1094
|
+
effect(() => {
|
|
1095
|
+
updateSvgIconNode(root, typeof source === "function" ? source() : source, props, options);
|
|
1096
|
+
});
|
|
1097
|
+
return root;
|
|
1098
|
+
}
|
|
1099
|
+
__name(createSvgIconNode, "createSvgIconNode");
|
|
1100
|
+
function updateSvgIconNode(root, definition, props, options) {
|
|
1101
|
+
const size = readProp2(props, "size", void 0);
|
|
1102
|
+
const width = readProp2(props, "width", size);
|
|
1103
|
+
const height = readProp2(props, "height", size);
|
|
1104
|
+
const normalizedWidth = normalizeSvgLength(width);
|
|
1105
|
+
const normalizedHeight = normalizeSvgLength(height);
|
|
1106
|
+
const userClass = [
|
|
1107
|
+
readProp2(props, "class", void 0),
|
|
1108
|
+
readProp2(props, "className", void 0)
|
|
1109
|
+
].filter(hasText).join(" ");
|
|
1110
|
+
const className = [options.class, options.className, userClass].filter(hasText).join(" ");
|
|
1111
|
+
setAttribute(root, "class", className);
|
|
1112
|
+
const internalStyle = size === void 0 ? "" : `width: ${normalizeCssLength(size)}; height: ${normalizeCssLength(size)}`;
|
|
1113
|
+
const userStyle = readProp2(props, "style", void 0);
|
|
1114
|
+
const style = [internalStyle, userStyle].filter(hasText).join("; ");
|
|
1115
|
+
setOptionalAttribute2(root, "style", style || void 0);
|
|
1116
|
+
const managedAttributes2 = /* @__PURE__ */ new Map();
|
|
1117
|
+
for (const name of Object.keys(props)) {
|
|
1118
|
+
if (name === "class" || name === "className" || name === "style" || name === "children") continue;
|
|
1119
|
+
if (!name.startsWith("aria-") && !name.startsWith("data-") && !["id", "title", "role", "tabIndex"].includes(name)) continue;
|
|
1120
|
+
const value = Reflect.get(props, name);
|
|
1121
|
+
if (value === void 0 || value === null || value === false) continue;
|
|
1122
|
+
managedAttributes2.set(name === "tabIndex" ? "tabindex" : name, String(value));
|
|
1123
|
+
}
|
|
1124
|
+
for (const [name, value] of managedAttributes2) setAttribute(root, name, value);
|
|
1125
|
+
clearStaleAttributes(root, managedAttributes2);
|
|
1126
|
+
const title = readProp2(props, "title", void 0);
|
|
1127
|
+
const ariaLabel = Reflect.get(props, "aria-label");
|
|
1128
|
+
const decorative = readProp2(props, "decorative", title === void 0 && ariaLabel === void 0);
|
|
1129
|
+
setOptionalAttribute2(root, "aria-hidden", decorative ? "true" : void 0);
|
|
1130
|
+
setOptionalAttribute2(root, "aria-label", ariaLabel === void 0 ? title : void 0);
|
|
1131
|
+
setOptionalAttribute2(root, "data-icon-name", options.dataIconName ?? definition?.name);
|
|
1132
|
+
setOptionalAttribute2(root, "color", readProp2(props, "color", void 0));
|
|
1133
|
+
if (!definition) {
|
|
1134
|
+
setProperty(root, "innerHTML", "");
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
const svgAttributes = {
|
|
1138
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1139
|
+
viewBox: definition.viewBox ?? "0 0 24 24",
|
|
1140
|
+
...options.defaultSvgAttributes,
|
|
1141
|
+
...definition.attributes,
|
|
1142
|
+
...normalizedWidth === void 0 ? {} : { width: normalizedWidth },
|
|
1143
|
+
...normalizedHeight === void 0 ? {} : { height: normalizedHeight },
|
|
1144
|
+
...readProp2(props, "color", void 0) === void 0 ? {} : { color: readProp2(props, "color", void 0) },
|
|
1145
|
+
...readProp2(props, "stroke", void 0) === void 0 ? {} : { stroke: readProp2(props, "stroke", void 0) },
|
|
1146
|
+
...readProp2(props, "fill", void 0) === void 0 ? {} : { fill: readProp2(props, "fill", void 0) },
|
|
1147
|
+
...readProp2(props, "strokeWidth", void 0) === void 0 ? {} : { "stroke-width": readProp2(props, "strokeWidth", void 0) }
|
|
1148
|
+
};
|
|
1149
|
+
const markup = Object.entries(svgAttributes).filter(([, value]) => value !== void 0).map(([name, value]) => `${name}="${escapeXml(String(value))}"`).join(" ");
|
|
1150
|
+
const titleMarkup = title === void 0 ? "" : `<title>${escapeXml(title)}</title>`;
|
|
1151
|
+
setProperty(root, "innerHTML", `<svg ${markup} aria-hidden="true">${titleMarkup}${definition.body}</svg>`);
|
|
1152
|
+
}
|
|
1153
|
+
__name(updateSvgIconNode, "updateSvgIconNode");
|
|
1154
|
+
function readProp2(props, name, fallback) {
|
|
1155
|
+
const value = Reflect.get(props, name);
|
|
1156
|
+
return value === void 0 ? fallback : value;
|
|
1157
|
+
}
|
|
1158
|
+
__name(readProp2, "readProp");
|
|
1159
|
+
function hasText(value) {
|
|
1160
|
+
return value !== void 0 && value.trim() !== "";
|
|
1161
|
+
}
|
|
1162
|
+
__name(hasText, "hasText");
|
|
1163
|
+
function normalizeSvgLength(value) {
|
|
1164
|
+
if (value === void 0) return void 0;
|
|
1165
|
+
return typeof value === "number" ? String(value) : value;
|
|
1166
|
+
}
|
|
1167
|
+
__name(normalizeSvgLength, "normalizeSvgLength");
|
|
1168
|
+
function normalizeCssLength(value) {
|
|
1169
|
+
return typeof value === "number" || /^\d+(?:\.\d+)?$/u.test(value) ? `${value}px` : value;
|
|
1170
|
+
}
|
|
1171
|
+
__name(normalizeCssLength, "normalizeCssLength");
|
|
1172
|
+
function setOptionalAttribute2(node, name, value) {
|
|
1173
|
+
if (value === void 0 || value === null || value === false || value === "") {
|
|
1174
|
+
node.removeAttribute(name);
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
setAttribute(node, name, String(value));
|
|
1178
|
+
}
|
|
1179
|
+
__name(setOptionalAttribute2, "setOptionalAttribute");
|
|
1180
|
+
function clearStaleAttributes(node, next) {
|
|
1181
|
+
const previous = node.__vobsIconAttributes ?? /* @__PURE__ */ new Set();
|
|
1182
|
+
for (const name of previous) {
|
|
1183
|
+
if (!next.has(name)) node.removeAttribute(name);
|
|
1184
|
+
}
|
|
1185
|
+
node.__vobsIconAttributes = new Set(next.keys());
|
|
1186
|
+
}
|
|
1187
|
+
__name(clearStaleAttributes, "clearStaleAttributes");
|
|
1188
|
+
function escapeXml(value) {
|
|
1189
|
+
return value.replace(/&/gu, "&").replace(/</gu, "<").replace(/>/gu, ">").replace(/"/gu, """);
|
|
1190
|
+
}
|
|
1191
|
+
__name(escapeXml, "escapeXml");
|
|
1192
|
+
|
|
1193
|
+
// packages/ui/src/icon.ts
|
|
1194
|
+
function Icon(props = {}) {
|
|
1195
|
+
const root = createSvgIconNode(() => {
|
|
1196
|
+
const definition = resolveIcon(
|
|
1197
|
+
readProp(props, "icon", void 0) ?? readProp(props, "name", void 0)
|
|
1198
|
+
);
|
|
1199
|
+
if (!definition) {
|
|
1200
|
+
if (hasProp(props, "children")) return void 0;
|
|
1201
|
+
throw new Error("Vobs UI: Icon requires a registered `name` or an `icon` definition");
|
|
1202
|
+
}
|
|
1203
|
+
return iconDefinitionToSvg(definition);
|
|
1204
|
+
}, props, {
|
|
1205
|
+
class: "vui-icon icon",
|
|
1206
|
+
defaultSvgAttributes: {
|
|
1207
|
+
fill: "none",
|
|
1208
|
+
stroke: "currentColor",
|
|
1209
|
+
"stroke-width": 2,
|
|
1210
|
+
"stroke-linecap": "butt",
|
|
1211
|
+
"stroke-linejoin": "miter"
|
|
1212
|
+
}
|
|
1213
|
+
});
|
|
1214
|
+
if (hasProp(props, "children")) mountSlot(root, props, "children");
|
|
1215
|
+
return root;
|
|
1216
|
+
}
|
|
1217
|
+
__name(Icon, "Icon");
|
|
1218
|
+
function iconDefinitionToSvg(definition) {
|
|
1219
|
+
return {
|
|
1220
|
+
name: definition.name,
|
|
1221
|
+
body: definition.path,
|
|
1222
|
+
viewBox: definition.viewBox
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
__name(iconDefinitionToSvg, "iconDefinitionToSvg");
|
|
1226
|
+
var VUI_ICON_PATHS = {
|
|
1227
|
+
search: '<circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/>',
|
|
1228
|
+
check: '<polyline points="4 12 10 18 20 6"/>',
|
|
1229
|
+
x: '<line x1="6" y1="6" x2="18" y2="18"/><line x1="18" y1="6" x2="6" y2="18"/>',
|
|
1230
|
+
plus: '<line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>',
|
|
1231
|
+
minus: '<line x1="5" y1="12" x2="19" y2="12"/>',
|
|
1232
|
+
"chevron-right": '<polyline points="9 6 15 12 9 18"/>',
|
|
1233
|
+
"chevron-down": '<polyline points="6 9 12 15 18 9"/>',
|
|
1234
|
+
"chevron-up": '<polyline points="6 15 12 9 18 15"/>',
|
|
1235
|
+
"chevron-left": '<polyline points="15 6 9 12 15 18"/>',
|
|
1236
|
+
"arrow-left": '<line x1="20" y1="12" x2="4" y2="12"/><polyline points="10 6 4 12 10 18"/>',
|
|
1237
|
+
"arrow-right": '<line x1="4" y1="12" x2="20" y2="12"/><polyline points="14 6 20 12 14 18"/>',
|
|
1238
|
+
"arrow-up": '<line x1="12" y1="20" x2="12" y2="4"/><polyline points="6 10 12 4 18 10"/>',
|
|
1239
|
+
"arrow-down": '<line x1="12" y1="4" x2="12" y2="20"/><polyline points="6 14 12 20 18 14"/>',
|
|
1240
|
+
atom: '<circle cx="12" cy="12" r="2"/><ellipse cx="12" cy="12" rx="10" ry="4"/><ellipse cx="12" cy="12" rx="10" ry="4" transform="rotate(60 12 12)"/><ellipse cx="12" cy="12" rx="10" ry="4" transform="rotate(120 12 12)"/>',
|
|
1241
|
+
globe: '<circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18"/>',
|
|
1242
|
+
"arrow-expand": '<polyline points="14 4 20 4 20 10"/><line x1="14" y1="10" x2="20" y2="4"/><polyline points="10 20 4 20 4 14"/><line x1="10" y1="14" x2="4" y2="20"/>',
|
|
1243
|
+
"arrow-minimize": '<polyline points="20 4 14 10 20 10"/><line x1="14" y1="10" x2="14" y2="4"/><polyline points="4 20 10 14 4 14"/><line x1="10" y1="14" x2="10" y2="20"/>',
|
|
1244
|
+
"check-circle": '<circle cx="12" cy="12" r="9"/><polyline points="8 12 11 15 16 9"/>',
|
|
1245
|
+
"alert-circle": '<circle cx="12" cy="12" r="9"/><line x1="12" y1="8" x2="12" y2="13"/><line x1="12" y1="16" x2="12" y2="16.01"/>',
|
|
1246
|
+
"alert-triangle": '<path d="M12 3 22 20 2 20 Z"/><line x1="12" y1="10" x2="12" y2="15"/><line x1="12" y1="18" x2="12" y2="18.01"/>',
|
|
1247
|
+
info: '<circle cx="12" cy="12" r="9"/><line x1="12" y1="11" x2="12" y2="16"/><line x1="12" y1="8" x2="12" y2="8.01"/>',
|
|
1248
|
+
home: '<polygon points="3 11 12 3 21 11 21 21 14 21 14 14 10 14 10 21 3 21 3 11"/>',
|
|
1249
|
+
user: '<path d="M4 21v-1a6 6 0 0 1 6-6h4a6 6 0 0 1 6 6v1"/><circle cx="12" cy="8" r="4"/>',
|
|
1250
|
+
settings: '<circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z"/>',
|
|
1251
|
+
menu: '<line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="20" y2="18"/>',
|
|
1252
|
+
"more-h": '<circle cx="5" cy="12" r="1.5" fill="currentColor"/><circle cx="12" cy="12" r="1.5" fill="currentColor"/><circle cx="19" cy="12" r="1.5" fill="currentColor"/>',
|
|
1253
|
+
calendar: '<rect x="3" y="5" width="18" height="16"/><line x1="3" y1="10" x2="21" y2="10"/><line x1="8" y1="3" x2="8" y2="7"/><line x1="16" y1="3" x2="16" y2="7"/>',
|
|
1254
|
+
filter: '<polygon points="3 4 21 4 14 12 14 20 10 18 10 12 3 4"/>',
|
|
1255
|
+
sort: '<path d="M8 20V4"/><polyline points="4 8 8 4 12 8"/><path d="M16 4v16"/><polyline points="12 16 16 20 20 16"/>',
|
|
1256
|
+
edit: '<path d="M4 20h4l10-10-4-4L4 16v4z"/><path d="M14 6l4 4"/>',
|
|
1257
|
+
trash: '<polyline points="4 6 20 6"/><path d="M6 6v14h12V6"/><path d="M9 6V4h6v2"/><line x1="10" y1="10" x2="10" y2="17"/><line x1="14" y1="10" x2="14" y2="17"/>',
|
|
1258
|
+
download: '<path d="M12 3v12"/><polyline points="7 10 12 15 17 10"/><line x1="3" y1="21" x2="21" y2="21"/>',
|
|
1259
|
+
upload: '<path d="M12 21V6"/><polyline points="7 11 12 6 17 11"/><line x1="3" y1="21" x2="21" y2="21"/>',
|
|
1260
|
+
pause: '<line x1="9" y1="5" x2="9" y2="19"/><line x1="15" y1="5" x2="15" y2="19"/>',
|
|
1261
|
+
play: '<polygon points="8 5 19 12 8 19 8 5"/>',
|
|
1262
|
+
refresh: '<polyline points="21 4 21 10 15 10"/><polyline points="3 20 3 14 9 14"/><path d="M20.5 9A9 9 0 0 0 5 5.5L3 7M3.5 15A9 9 0 0 0 19 18.5L21 17"/>',
|
|
1263
|
+
bell: '<path d="M6 8a6 6 0 0 1 12 0c0 7 3 8 3 8H3s3-1 3-8z"/><path d="M10 21a2 2 0 0 0 4 0"/>',
|
|
1264
|
+
folder: '<path d="M3 6h6l2 3h10v10H3z"/>',
|
|
1265
|
+
code: '<polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/>',
|
|
1266
|
+
sparkles: '<path d="M12 3l1.8 4.2L18 9l-4.2 1.8L12 15l-1.8-4.2L6 9l4.2-1.8L12 3z"/><path d="M19 14l1 2.2 2.2 1-2.2 1L19 20.4l-1-2.2-2.2-1 2.2-1L19 14z"/>',
|
|
1267
|
+
zap: '<polygon points="13 2 4 14 12 14 11 22 20 10 12 10 13 2"/>',
|
|
1268
|
+
sun: '<circle cx="12" cy="12" r="4"/><line x1="12" y1="2" x2="12" y2="5"/><line x1="12" y1="19" x2="12" y2="22"/><line x1="2" y1="12" x2="5" y2="12"/><line x1="19" y1="12" x2="22" y2="12"/><line x1="4.6" y1="4.6" x2="6.7" y2="6.7"/><line x1="17.3" y1="17.3" x2="19.4" y2="19.4"/><line x1="4.6" y1="19.4" x2="6.7" y2="17.3"/><line x1="17.3" y1="6.7" x2="19.4" y2="4.6"/>',
|
|
1269
|
+
moon: '<path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/>',
|
|
1270
|
+
terminal: '<polyline points="4 7 9 12 4 17"/><line x1="12" y1="17" x2="20" y2="17"/>'
|
|
1271
|
+
};
|
|
1272
|
+
var iconRegistry = new Map(
|
|
1273
|
+
Object.entries(VUI_ICON_PATHS).map(([name, path]) => [name, { name, path }])
|
|
1274
|
+
);
|
|
1275
|
+
function resolveIcon(icon) {
|
|
1276
|
+
return typeof icon === "string" ? iconRegistry.get(icon) : icon;
|
|
1277
|
+
}
|
|
1278
|
+
__name(resolveIcon, "resolveIcon");
|
|
1279
|
+
|
|
1280
|
+
// packages/devtools-ui/src/panel.tsx
|
|
1281
|
+
var EMPTY_SNAPSHOT = {
|
|
1282
|
+
api: null,
|
|
1283
|
+
tree: [],
|
|
1284
|
+
signals: [],
|
|
1285
|
+
effects: [],
|
|
1286
|
+
updates: [],
|
|
1287
|
+
lifecycle: [],
|
|
1288
|
+
network: [],
|
|
1289
|
+
errors: [],
|
|
1290
|
+
metrics: null,
|
|
1291
|
+
performanceEntries: [],
|
|
1292
|
+
memory: null,
|
|
1293
|
+
router: null,
|
|
1294
|
+
routerContext: null
|
|
1295
|
+
};
|
|
1296
|
+
var PANEL_REFRESH_EVENTS = ["signal-update", "update", "lifecycle", "network-request", "router", "error", "collection", "collection-cleared"];
|
|
1297
|
+
function readDevToolsSnapshot(api = getDevTools()) {
|
|
1298
|
+
return readDevToolsSnapshotWithRouter(api, null);
|
|
1299
|
+
}
|
|
1300
|
+
__name(readDevToolsSnapshot, "readDevToolsSnapshot");
|
|
1301
|
+
function readDevToolsSnapshotWithRouter(api, router) {
|
|
1302
|
+
if (!api) return { ...EMPTY_SNAPSHOT, router: router?.devtools ?? null };
|
|
1303
|
+
return {
|
|
1304
|
+
api,
|
|
1305
|
+
tree: api.getComponentTree(),
|
|
1306
|
+
signals: api.getSignals(),
|
|
1307
|
+
effects: api.getEffects(),
|
|
1308
|
+
updates: api.getUpdates(),
|
|
1309
|
+
lifecycle: api.getLifecycleEvents(),
|
|
1310
|
+
network: api.getNetworkRequests(),
|
|
1311
|
+
errors: api.getErrors(),
|
|
1312
|
+
metrics: api.getPerformanceMetrics(),
|
|
1313
|
+
performanceEntries: api.getPerformanceEntries(),
|
|
1314
|
+
memory: api.takeMemorySnapshot(),
|
|
1315
|
+
router: router?.devtools ?? null,
|
|
1316
|
+
routerContext: api.getRouterContext()
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1319
|
+
__name(readDevToolsSnapshotWithRouter, "readDevToolsSnapshotWithRouter");
|
|
1320
|
+
function DevToolsPanel(props = {}) {
|
|
1321
|
+
const refreshCount = state(0);
|
|
1322
|
+
const activeSection = state("updates");
|
|
1323
|
+
const activeAdvancedSection = state("signals");
|
|
1324
|
+
const activeRouterTab = state("context");
|
|
1325
|
+
const activeUpdatesTab = state("updates");
|
|
1326
|
+
const activeComponentsTab = state("tree");
|
|
1327
|
+
const activeRouteView = state("tree");
|
|
1328
|
+
const activeTimelineFilter = state("all");
|
|
1329
|
+
const networkSelection = state(null);
|
|
1330
|
+
const networkSourceFilter = state("all");
|
|
1331
|
+
const networkStatusFilter = state("all");
|
|
1332
|
+
const networkDetailTab = state("overview");
|
|
1333
|
+
const networkTesterOpen = state(false);
|
|
1334
|
+
const networkTesterRevision = state(0);
|
|
1335
|
+
const networkTesterRun = state({ status: "idle" });
|
|
1336
|
+
const networkTesterTab = state("params");
|
|
1337
|
+
let networkTesterDraft = createRequestTesterDraft();
|
|
1338
|
+
const selection = state(null);
|
|
1339
|
+
const query = props.query ?? state("");
|
|
1340
|
+
const http = props.http ?? inject(HTTP_KEY) ?? null;
|
|
1341
|
+
let refreshInvalidating = false;
|
|
1342
|
+
const notifyRefresh = /* @__PURE__ */ __name(() => {
|
|
1343
|
+
if (refreshInvalidating) return;
|
|
1344
|
+
refreshInvalidating = true;
|
|
1345
|
+
refreshCount.value++;
|
|
1346
|
+
queueMicrotask(() => {
|
|
1347
|
+
refreshInvalidating = false;
|
|
1348
|
+
});
|
|
1349
|
+
}, "notifyRefresh");
|
|
1350
|
+
queueMicrotask(notifyRefresh);
|
|
1351
|
+
const api = resolveApi(props);
|
|
1352
|
+
if (api) {
|
|
1353
|
+
const stops = PANEL_REFRESH_EVENTS.map((event) => api.subscribe(event, notifyRefresh));
|
|
1354
|
+
onDispose(() => {
|
|
1355
|
+
for (const stop of stops) stop();
|
|
1356
|
+
});
|
|
1357
|
+
}
|
|
1358
|
+
const router = props.router ?? null;
|
|
1359
|
+
if (router) {
|
|
1360
|
+
const detachRouter = api?.attachRouter(router);
|
|
1361
|
+
const stopNavigationStart = router.devtools.subscribe("navigation:start", notifyRefresh);
|
|
1362
|
+
const stopNavigation = router.devtools.subscribe("navigation:end", notifyRefresh);
|
|
1363
|
+
const stopRouteUpdate = router.devtools.subscribe("route:update", notifyRefresh);
|
|
1364
|
+
const stopRouteError = router.devtools.subscribe("error", notifyRefresh);
|
|
1365
|
+
onDispose(() => {
|
|
1366
|
+
stopNavigationStart();
|
|
1367
|
+
stopNavigation();
|
|
1368
|
+
stopRouteUpdate();
|
|
1369
|
+
stopRouteError();
|
|
1370
|
+
detachRouter?.();
|
|
1371
|
+
});
|
|
1372
|
+
}
|
|
1373
|
+
const toolbarPlacement = props.toolbarPlacement ?? "content";
|
|
1374
|
+
return /* @__PURE__ */ React.createElement("div", { class: "vobs-devtools-shell" }, /* @__PURE__ */ React.createElement("aside", { class: "vobs-devtools-shell__rail", "aria-label": "DevTools sections" }, /* @__PURE__ */ React.createElement("div", { class: "vobs-devtools-shell__mark" }, /* @__PURE__ */ React.createElement(Icon, { name: "code" })), /* @__PURE__ */ React.createElement(SectionNav, { activeSection })), /* @__PURE__ */ React.createElement("section", { class: "vobs-devtools-shell__main" }, /* @__PURE__ */ React.createElement("div", { class: "vobs-devtools-shell__content" }, toolbarPlacement === "content" ? /* @__PURE__ */ React.createElement(DevToolsToolbar, { api, query }) : null, /* @__PURE__ */ React.createElement(DevToolsContent, { refreshCount, activeSection, activeAdvancedSection, activeRouterTab, activeUpdatesTab, activeComponentsTab, activeRouteView, router, api, http, selection, query, networkSelection, networkSourceFilter, networkStatusFilter, networkDetailTab, networkTesterOpen, networkTesterRevision, networkTesterRun, networkTesterDraft, networkTesterTab }))), /* @__PURE__ */ React.createElement(ActivityRail, { refreshCount, router, api, selection, activeSection, activeFilter: activeTimelineFilter }));
|
|
1375
|
+
}
|
|
1376
|
+
__name(DevToolsPanel, "DevToolsPanel");
|
|
1377
|
+
function DevToolsToolbar(props) {
|
|
1378
|
+
const refreshCount = state(0);
|
|
1379
|
+
if (props.api) {
|
|
1380
|
+
const stops = ["collection", "collection-cleared"].map((event) => props.api.subscribe(event, () => {
|
|
1381
|
+
refreshCount.value++;
|
|
1382
|
+
}));
|
|
1383
|
+
onDispose(() => {
|
|
1384
|
+
for (const stop of stops) stop();
|
|
1385
|
+
});
|
|
1386
|
+
}
|
|
1387
|
+
return createFragment((parent, anchor) => {
|
|
1388
|
+
const toolbar = createElement("div");
|
|
1389
|
+
setAttribute(toolbar, "class", "vobs-devtools-collection-toolbar vobs-devtools-collection-toolbar--header");
|
|
1390
|
+
const search = createElement("input");
|
|
1391
|
+
setAttribute(search, "class", "vobs-devtools-search vobs-devtools-header-search");
|
|
1392
|
+
setAttribute(search, "type", "search");
|
|
1393
|
+
setAttribute(search, "placeholder", "Search diagnostics");
|
|
1394
|
+
effect(() => {
|
|
1395
|
+
const next = props.query.value;
|
|
1396
|
+
if (search.value !== next) setProperty(search, "value", next);
|
|
1397
|
+
});
|
|
1398
|
+
search.addEventListener("input", () => {
|
|
1399
|
+
props.query.value = search.value;
|
|
1400
|
+
});
|
|
1401
|
+
insertBefore(toolbar, search, null);
|
|
1402
|
+
const actions = createElement("div");
|
|
1403
|
+
setAttribute(actions, "class", "vobs-devtools-collection-toolbar__actions");
|
|
1404
|
+
insertBefore(toolbar, actions, null);
|
|
1405
|
+
insertBefore(parent, toolbar, anchor);
|
|
1406
|
+
insertDynamic(actions, null, () => {
|
|
1407
|
+
void refreshCount.value;
|
|
1408
|
+
if (!props.api) return null;
|
|
1409
|
+
const paused = props.api.getCollectionState().paused;
|
|
1410
|
+
return createFragment((actionParent, actionAnchor) => {
|
|
1411
|
+
insertBefore(actionParent, createComponent(Button, {
|
|
1412
|
+
variant: paused ? "warning" : "secondary",
|
|
1413
|
+
iconOnly: true,
|
|
1414
|
+
icon: createComponent(Icon, { name: paused ? "play" : "pause" }),
|
|
1415
|
+
"aria-label": paused ? "Resume collection" : "Pause collection",
|
|
1416
|
+
title: paused ? "Resume collection" : "Pause collection",
|
|
1417
|
+
onClick: /* @__PURE__ */ __name(() => props.api?.setCollectionPaused(!paused), "onClick")
|
|
1418
|
+
}), actionAnchor);
|
|
1419
|
+
insertBefore(actionParent, createComponent(Button, {
|
|
1420
|
+
variant: "danger-subtle",
|
|
1421
|
+
iconOnly: true,
|
|
1422
|
+
icon: createComponent(Icon, { name: "trash" }),
|
|
1423
|
+
"aria-label": "Clear diagnostics",
|
|
1424
|
+
title: "Clear diagnostics",
|
|
1425
|
+
onClick: /* @__PURE__ */ __name(() => {
|
|
1426
|
+
props.api?.clearUpdates();
|
|
1427
|
+
props.api?.clearNetworkRequests();
|
|
1428
|
+
props.api?.clearErrors();
|
|
1429
|
+
props.api?.clearLifecycleEvents();
|
|
1430
|
+
}, "onClick")
|
|
1431
|
+
}), actionAnchor);
|
|
1432
|
+
const exportDiagnostics = /* @__PURE__ */ __name(() => {
|
|
1433
|
+
const data = JSON.stringify(props.api?.exportDiagnostics(), null, 2);
|
|
1434
|
+
if (typeof document === "undefined" || typeof URL === "undefined" || typeof URL.createObjectURL !== "function" || typeof URL.revokeObjectURL !== "function" || typeof Blob === "undefined") return;
|
|
1435
|
+
const link = document.createElement("a");
|
|
1436
|
+
link.href = URL.createObjectURL(new Blob([data], { type: "application/json" }));
|
|
1437
|
+
link.download = `vobs-devtools-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.json`;
|
|
1438
|
+
link.click();
|
|
1439
|
+
URL.revokeObjectURL(link.href);
|
|
1440
|
+
}, "exportDiagnostics");
|
|
1441
|
+
insertBefore(actionParent, createComponent(Button, {
|
|
1442
|
+
variant: "ghost",
|
|
1443
|
+
iconOnly: true,
|
|
1444
|
+
icon: createComponent(Icon, { name: "download" }),
|
|
1445
|
+
"aria-label": "Export diagnostics",
|
|
1446
|
+
title: "Export diagnostics",
|
|
1447
|
+
onClick: exportDiagnostics
|
|
1448
|
+
}), actionAnchor);
|
|
1449
|
+
const importInput = createElement("input");
|
|
1450
|
+
setAttribute(importInput, "type", "file");
|
|
1451
|
+
setAttribute(importInput, "accept", "application/json,.json");
|
|
1452
|
+
setAttribute(importInput, "aria-label", "Import diagnostics");
|
|
1453
|
+
setAttribute(importInput, "hidden", "");
|
|
1454
|
+
importInput.addEventListener("change", () => {
|
|
1455
|
+
const file = importInput.files?.[0];
|
|
1456
|
+
if (!file) return;
|
|
1457
|
+
void file.text().then((text) => props.api?.importDiagnostics(JSON.parse(text))).catch((error) => props.api?.reportError("global", error));
|
|
1458
|
+
});
|
|
1459
|
+
insertBefore(actionParent, importInput, actionAnchor);
|
|
1460
|
+
insertBefore(actionParent, createComponent(Button, {
|
|
1461
|
+
variant: "ghost",
|
|
1462
|
+
iconOnly: true,
|
|
1463
|
+
icon: createComponent(Icon, { name: "upload" }),
|
|
1464
|
+
"aria-label": "Import diagnostics",
|
|
1465
|
+
title: "Import diagnostics",
|
|
1466
|
+
onClick: /* @__PURE__ */ __name(() => importInput.click(), "onClick")
|
|
1467
|
+
}), actionAnchor);
|
|
1468
|
+
if (props.onToggleMaximize) insertBefore(actionParent, createComponent(Button, {
|
|
1469
|
+
variant: "ghost",
|
|
1470
|
+
iconOnly: true,
|
|
1471
|
+
icon: createComponent(Icon, { name: props.maximized ? "arrow-minimize" : "arrow-expand" }),
|
|
1472
|
+
"aria-label": props.maximized ? "Restore DevTools" : "Maximize DevTools",
|
|
1473
|
+
title: props.maximized ? "Restore DevTools" : "Maximize DevTools",
|
|
1474
|
+
onClick: props.onToggleMaximize
|
|
1475
|
+
}), actionAnchor);
|
|
1476
|
+
});
|
|
1477
|
+
});
|
|
1478
|
+
});
|
|
1479
|
+
}
|
|
1480
|
+
__name(DevToolsToolbar, "DevToolsToolbar");
|
|
1481
|
+
function createRequestTesterDraft(url = "") {
|
|
1482
|
+
return { url, method: "GET", params: [{ key: "", value: "" }], headers: [{ key: "", value: "" }], body: "" };
|
|
1483
|
+
}
|
|
1484
|
+
__name(createRequestTesterDraft, "createRequestTesterDraft");
|
|
1485
|
+
var TIMELINE_FILTER_OPTIONS = [
|
|
1486
|
+
{ value: "all", label: "All events" },
|
|
1487
|
+
{ value: "update", label: "Updates" },
|
|
1488
|
+
{ value: "request", label: "Requests" },
|
|
1489
|
+
{ value: "navigation", label: "Navigation" },
|
|
1490
|
+
{ value: "error", label: "Errors" }
|
|
1491
|
+
];
|
|
1492
|
+
function resolveApi(props) {
|
|
1493
|
+
return props.api === void 0 ? getDevTools() : props.api;
|
|
1494
|
+
}
|
|
1495
|
+
__name(resolveApi, "resolveApi");
|
|
1496
|
+
function DevToolsContent(props) {
|
|
1497
|
+
return createFragment((parent, anchor) => {
|
|
1498
|
+
insertDynamic(parent, anchor, () => {
|
|
1499
|
+
void props.refreshCount.value;
|
|
1500
|
+
void props.activeSection.value;
|
|
1501
|
+
void props.activeRouterTab.value;
|
|
1502
|
+
void props.activeUpdatesTab.value;
|
|
1503
|
+
void props.activeComponentsTab.value;
|
|
1504
|
+
void props.activeRouteView.value;
|
|
1505
|
+
void props.query.value;
|
|
1506
|
+
void props.networkSelection.value;
|
|
1507
|
+
void props.networkSourceFilter.value;
|
|
1508
|
+
void props.networkStatusFilter.value;
|
|
1509
|
+
void props.networkDetailTab.value;
|
|
1510
|
+
void props.networkTesterOpen.value;
|
|
1511
|
+
void props.networkTesterRevision.value;
|
|
1512
|
+
void props.networkTesterRun.value;
|
|
1513
|
+
void props.networkTesterTab.value;
|
|
1514
|
+
const selected = props.selection.value;
|
|
1515
|
+
const snapshot = readDevToolsSnapshotWithRouter(props.api, props.router);
|
|
1516
|
+
return renderDevToolsContent(snapshot, props.activeSection.value, props.router, props.activeRouterTab, props.activeUpdatesTab, props.activeComponentsTab, selected, focusSelection(props.activeSection, props.selection), props.query.value, props.activeAdvancedSection, props.activeRouteView, props.networkSelection, props.networkSourceFilter, props.networkStatusFilter, props.networkDetailTab, props.query, props.http, props.networkTesterOpen, props.networkTesterRevision, props.networkTesterRun, props.networkTesterDraft, props.networkTesterTab);
|
|
1517
|
+
});
|
|
1518
|
+
});
|
|
1519
|
+
}
|
|
1520
|
+
__name(DevToolsContent, "DevToolsContent");
|
|
1521
|
+
function ActivityRail(props) {
|
|
1522
|
+
return createFragment((parent, anchor) => {
|
|
1523
|
+
insertDynamic(parent, anchor, () => {
|
|
1524
|
+
void props.refreshCount.value;
|
|
1525
|
+
const filter = props.activeFilter.value;
|
|
1526
|
+
const selected = props.selection.value;
|
|
1527
|
+
const snapshot = readDevToolsSnapshotWithRouter(props.api, props.router);
|
|
1528
|
+
const updates = [...snapshot.updates].reverse().slice(0, 8);
|
|
1529
|
+
const timeline = collectActivityTimeline(snapshot, props.router, filter);
|
|
1530
|
+
return renderActivityRail(updates, timeline, snapshot.api, selected, filter, (next) => {
|
|
1531
|
+
props.activeFilter.value = next;
|
|
1532
|
+
}, focusSelection(props.activeSection, props.selection));
|
|
1533
|
+
});
|
|
1534
|
+
});
|
|
1535
|
+
}
|
|
1536
|
+
__name(ActivityRail, "ActivityRail");
|
|
1537
|
+
function focusSelection(activeSection, selection) {
|
|
1538
|
+
return (section, next) => {
|
|
1539
|
+
selection.value = next;
|
|
1540
|
+
activeSection.value = section;
|
|
1541
|
+
};
|
|
1542
|
+
}
|
|
1543
|
+
__name(focusSelection, "focusSelection");
|
|
1544
|
+
function SectionNav(props) {
|
|
1545
|
+
return createFragment((parent, anchor) => {
|
|
1546
|
+
insertDynamic(parent, anchor, () => {
|
|
1547
|
+
const selected = props.activeSection.value;
|
|
1548
|
+
return createFragment((navParent, navAnchor) => {
|
|
1549
|
+
for (const section of ["updates", "components", "advanced", "network", "errors", "router"]) {
|
|
1550
|
+
const label = section === "components" ? "comp..." : section === "advanced" ? "adv..." : section;
|
|
1551
|
+
const button = createElement("button");
|
|
1552
|
+
setAttribute(button, "class", `vobs-devtools-shell__nav-item${selected === section ? " is-active" : ""}`);
|
|
1553
|
+
setAttribute(button, "type", "button");
|
|
1554
|
+
const accessibleLabel = section === "advanced" ? "Advanced" : section;
|
|
1555
|
+
setAttribute(button, "aria-label", accessibleLabel);
|
|
1556
|
+
setAttribute(button, "title", accessibleLabel);
|
|
1557
|
+
setAttribute(button, "aria-pressed", selected === section ? "true" : "false");
|
|
1558
|
+
insertBefore(button, createComponent(Icon, { name: section === "router" ? "folder" : section === "components" ? "code" : section === "advanced" ? "atom" : section === "network" ? "globe" : section === "errors" ? "alert-triangle" : "refresh" }), null);
|
|
1559
|
+
insertBefore(button, createElementText(label), null);
|
|
1560
|
+
button.addEventListener("click", () => {
|
|
1561
|
+
props.activeSection.value = section;
|
|
1562
|
+
});
|
|
1563
|
+
insertBefore(navParent, button, navAnchor);
|
|
1564
|
+
}
|
|
1565
|
+
});
|
|
1566
|
+
});
|
|
1567
|
+
});
|
|
1568
|
+
}
|
|
1569
|
+
__name(SectionNav, "SectionNav");
|
|
1570
|
+
function collectActivityTimeline(snapshot, router, filter = "all") {
|
|
1571
|
+
const items = snapshot.updates.map((update) => ({
|
|
1572
|
+
kind: "update",
|
|
1573
|
+
timestamp: update.timestamp,
|
|
1574
|
+
title: snapshot.api?.getSignal(update.signalId) ? displaySignalName(snapshot.api.getSignal(update.signalId)) : displayDebugName(update.signalName),
|
|
1575
|
+
detail: `${formatDebugSource(snapshot.api?.getSignal(update.signalId)?.component ?? "unknown")} \xB7 ${update.duration.toFixed(2)} ms \xB7 ${update.effects.length} effects`,
|
|
1576
|
+
icon: "zap",
|
|
1577
|
+
update
|
|
1578
|
+
}));
|
|
1579
|
+
for (const request of snapshot.network) {
|
|
1580
|
+
items.push({
|
|
1581
|
+
kind: "request",
|
|
1582
|
+
timestamp: request.startedAt,
|
|
1583
|
+
title: `${request.method} ${request.url}`,
|
|
1584
|
+
detail: `${request.source ?? "http"} \xB7 ${request.status}${request.duration === void 0 ? "" : ` \xB7 ${request.duration} ms`}`,
|
|
1585
|
+
icon: "download"
|
|
1586
|
+
});
|
|
1587
|
+
}
|
|
1588
|
+
for (const request of snapshot.routerContext?.dataRequests ?? []) {
|
|
1589
|
+
items.push({
|
|
1590
|
+
kind: "request",
|
|
1591
|
+
timestamp: request.startedAt ?? Date.now(),
|
|
1592
|
+
title: `${request.kind} \xB7 ${request.key}`,
|
|
1593
|
+
detail: `${request.status}${request.route ? ` \xB7 ${request.route}` : ""}`,
|
|
1594
|
+
icon: "folder"
|
|
1595
|
+
});
|
|
1596
|
+
}
|
|
1597
|
+
for (const trace of router?.devtools.getNavigationHistory() ?? []) {
|
|
1598
|
+
items.push({
|
|
1599
|
+
kind: "navigation",
|
|
1600
|
+
timestamp: trace.endedAt,
|
|
1601
|
+
title: `Navigation ${trace.to}`,
|
|
1602
|
+
detail: `${trace.status} \xB7 ${trace.duration.toFixed(2)} ms`,
|
|
1603
|
+
icon: "arrow-right"
|
|
1604
|
+
});
|
|
1605
|
+
}
|
|
1606
|
+
for (const error of snapshot.errors) {
|
|
1607
|
+
items.push({
|
|
1608
|
+
kind: "error",
|
|
1609
|
+
timestamp: error.lastOccurredAt,
|
|
1610
|
+
title: `${error.phase} \xB7 ${error.message}`,
|
|
1611
|
+
detail: error.route ?? error.component,
|
|
1612
|
+
icon: "alert-triangle"
|
|
1613
|
+
});
|
|
1614
|
+
}
|
|
1615
|
+
return items.filter((item) => filter === "all" || item.kind === filter).sort((left, right) => right.timestamp - left.timestamp).slice(0, 12);
|
|
1616
|
+
}
|
|
1617
|
+
__name(collectActivityTimeline, "collectActivityTimeline");
|
|
1618
|
+
function renderActivityRail(updates, timeline, api, selection, filter, onFilterChange, onFocus) {
|
|
1619
|
+
const root = createElement("aside");
|
|
1620
|
+
setAttribute(root, "class", "vobs-devtools-shell__activity");
|
|
1621
|
+
const header = createElement("div");
|
|
1622
|
+
setAttribute(header, "class", "vobs-devtools-shell__activity-header");
|
|
1623
|
+
const title = createElement("div");
|
|
1624
|
+
setAttribute(title, "class", "vobs-devtools-shell__activity-title");
|
|
1625
|
+
insertBefore(title, createElementText("Timeline"), null);
|
|
1626
|
+
insertBefore(header, title, null);
|
|
1627
|
+
insertBefore(header, createComponent(Select, {
|
|
1628
|
+
class: "vobs-devtools-timeline-filter",
|
|
1629
|
+
value: filter,
|
|
1630
|
+
"aria-label": "Filter timeline events",
|
|
1631
|
+
onChange: /* @__PURE__ */ __name((event) => {
|
|
1632
|
+
const next = event.target.value;
|
|
1633
|
+
if (isTimelineFilter(next)) onFilterChange(next);
|
|
1634
|
+
}, "onChange"),
|
|
1635
|
+
children: /* @__PURE__ */ __name(() => createFragment((parent, anchor) => {
|
|
1636
|
+
for (const option of TIMELINE_FILTER_OPTIONS) {
|
|
1637
|
+
const optionNode = createElement("option");
|
|
1638
|
+
setAttribute(optionNode, "value", option.value);
|
|
1639
|
+
insertBefore(optionNode, createText(option.label), null);
|
|
1640
|
+
insertBefore(parent, optionNode, anchor);
|
|
1641
|
+
}
|
|
1642
|
+
}), "children")
|
|
1643
|
+
}), null);
|
|
1644
|
+
insertBefore(root, header, null);
|
|
1645
|
+
const subtitle = createElement("div");
|
|
1646
|
+
setAttribute(subtitle, "class", "vobs-devtools-shell__activity-subtitle");
|
|
1647
|
+
insertBefore(subtitle, createElementText(`${timeline.length} shown \xB7 ${updates.length} updates`), null);
|
|
1648
|
+
insertBefore(root, subtitle, null);
|
|
1649
|
+
const list = createElement("div");
|
|
1650
|
+
setAttribute(list, "class", "vobs-devtools-activity-list");
|
|
1651
|
+
for (const entry of timeline) {
|
|
1652
|
+
const update = entry.update;
|
|
1653
|
+
const activityItem = createElement("div");
|
|
1654
|
+
setAttribute(activityItem, "class", `vobs-devtools-activity-item${update && selection?.type === "update" && selection.id === update.id ? " is-selected" : ""}`);
|
|
1655
|
+
if (update) activityItem.addEventListener("click", () => onFocus("updates", { type: "update", id: update.id }));
|
|
1656
|
+
const dot = createElement("span");
|
|
1657
|
+
setAttribute(dot, "class", "vobs-devtools-activity-item__dot");
|
|
1658
|
+
insertBefore(dot, createComponent(Icon, { name: entry.icon }), null);
|
|
1659
|
+
const body = createElement("div");
|
|
1660
|
+
setAttribute(body, "class", "vobs-devtools-activity-item__body");
|
|
1661
|
+
const name = createElement("span");
|
|
1662
|
+
setAttribute(name, "class", "vobs-devtools-activity-item__name");
|
|
1663
|
+
const signal = update ? api?.getSignal(update.signalId) : void 0;
|
|
1664
|
+
insertBefore(name, createElementText(entry.title), null);
|
|
1665
|
+
const detail = createElement("span");
|
|
1666
|
+
insertBefore(detail, createElementText(entry.detail ?? (update ? `${formatDebugSource(signal?.component ?? "unknown")} \xB7 ${update.duration.toFixed(2)} ms \xB7 ${update.effects.length} effects` : "")), null);
|
|
1667
|
+
insertBefore(body, name, null);
|
|
1668
|
+
insertBefore(body, detail, null);
|
|
1669
|
+
insertBefore(activityItem, dot, null);
|
|
1670
|
+
insertBefore(activityItem, body, null);
|
|
1671
|
+
insertBefore(list, activityItem, null);
|
|
1672
|
+
}
|
|
1673
|
+
if (timeline.length === 0) {
|
|
1674
|
+
const empty = createElement("span");
|
|
1675
|
+
setAttribute(empty, "class", "vobs-devtools-muted");
|
|
1676
|
+
insertBefore(empty, createElementText(filter === "all" ? "No recent events." : `No ${timelineFilterLabel(filter).toLowerCase()} events.`), null);
|
|
1677
|
+
insertBefore(list, empty, null);
|
|
1678
|
+
}
|
|
1679
|
+
insertBefore(root, list, null);
|
|
1680
|
+
return root;
|
|
1681
|
+
}
|
|
1682
|
+
__name(renderActivityRail, "renderActivityRail");
|
|
1683
|
+
function isTimelineFilter(value) {
|
|
1684
|
+
return TIMELINE_FILTER_OPTIONS.some((option) => option.value === value);
|
|
1685
|
+
}
|
|
1686
|
+
__name(isTimelineFilter, "isTimelineFilter");
|
|
1687
|
+
function timelineFilterLabel(filter) {
|
|
1688
|
+
return TIMELINE_FILTER_OPTIONS.find((option) => option.value === filter)?.label ?? "All events";
|
|
1689
|
+
}
|
|
1690
|
+
__name(timelineFilterLabel, "timelineFilterLabel");
|
|
1691
|
+
function createElementText(value) {
|
|
1692
|
+
return createText(value);
|
|
1693
|
+
}
|
|
1694
|
+
__name(createElementText, "createElementText");
|
|
1695
|
+
function renderDevToolsContent(snapshot, section = "updates", router = null, activeRouterTab, activeUpdatesTab, activeComponentsTab, selection = null, onFocus = () => void 0, query = "", activeAdvancedSection, activeRouteView, networkSelection, networkSourceFilter, networkStatusFilter, networkDetailTab, queryState, http, networkTesterOpen, networkTesterRevision, networkTesterRun, networkTesterDraft, networkTesterTab) {
|
|
1696
|
+
if (!snapshot.api) {
|
|
1697
|
+
return createComponent(Alert, {
|
|
1698
|
+
description: "Enable the devtools plugin to inspect the runtime."
|
|
1699
|
+
});
|
|
1700
|
+
}
|
|
1701
|
+
return renderFocusedSection(snapshot, section, router, activeRouterTab, activeUpdatesTab, activeComponentsTab, selection, onFocus, query, activeAdvancedSection, activeRouteView, networkSelection, networkSourceFilter, networkStatusFilter, networkDetailTab, queryState, http, networkTesterOpen, networkTesterRevision, networkTesterRun, networkTesterDraft, networkTesterTab);
|
|
1702
|
+
}
|
|
1703
|
+
__name(renderDevToolsContent, "renderDevToolsContent");
|
|
1704
|
+
function renderFocusedSection(snapshot, section, router, activeRouterTab, activeUpdatesTab, activeComponentsTab, selection = null, onFocus = () => void 0, query = "", activeAdvancedSection, activeRouteView, networkSelection, networkSourceFilter, networkStatusFilter, networkDetailTab, queryState, http, networkTesterOpen, networkTesterRevision, networkTesterRun, networkTesterDraft, networkTesterTab) {
|
|
1705
|
+
if (section === "router") return renderRouterSection(router, activeRouterTab, activeRouteView);
|
|
1706
|
+
if (section === "updates") return renderUpdatesSection(snapshot, activeUpdatesTab, query, selection, onFocus);
|
|
1707
|
+
if (section === "components") return renderComponentsSection(snapshot, activeComponentsTab, query, selection, onFocus);
|
|
1708
|
+
if (section === "network") return createComponent(Card, {
|
|
1709
|
+
children: /* @__PURE__ */ __name(() => renderUnifiedNetworkRequests(snapshot.network, snapshot.routerContext?.dataRequests ?? [], query, selection, onFocus, networkSelection, networkSourceFilter, networkStatusFilter, networkDetailTab, snapshot.api, queryState, http, networkTesterOpen, networkTesterRevision, networkTesterRun, networkTesterDraft, snapshot.routerContext?.route, networkTesterTab), "children")
|
|
1710
|
+
});
|
|
1711
|
+
if (section === "errors") return createComponent(Card, {
|
|
1712
|
+
description: `${snapshot.errors.length} retained unique errors`,
|
|
1713
|
+
children: /* @__PURE__ */ __name(() => renderErrors(filterErrors(snapshot.errors, query), selection, onFocus), "children")
|
|
1714
|
+
});
|
|
1715
|
+
if (section === "advanced") return renderAdvancedSection(snapshot, activeAdvancedSection, query);
|
|
1716
|
+
const list = createElement("div");
|
|
1717
|
+
setAttribute(list, "class", "vobs-devtools-list");
|
|
1718
|
+
let title = "Recent updates";
|
|
1719
|
+
let description = `${snapshot.updates.length} retained traces`;
|
|
1720
|
+
return createComponent(Card, { title, description, children: /* @__PURE__ */ __name(() => list, "children") });
|
|
1721
|
+
}
|
|
1722
|
+
__name(renderFocusedSection, "renderFocusedSection");
|
|
1723
|
+
function renderComponentsSection(snapshot, activeTab, query = "", selection = null, onFocus = () => void 0) {
|
|
1724
|
+
const tabs = createComponent(Tabs, {
|
|
1725
|
+
class: "vobs-devtools-router-tabs",
|
|
1726
|
+
variant: "filled",
|
|
1727
|
+
items: [
|
|
1728
|
+
{ id: "tree", label: "Component tree", content: /* @__PURE__ */ __name(() => renderComponentTree(snapshot, query, selection, onFocus), "content") },
|
|
1729
|
+
{ id: "lifecycle", label: "Lifecycle timeline", content: /* @__PURE__ */ __name(() => createComponent(Card, {
|
|
1730
|
+
class: "vobs-devtools-lifecycle-card",
|
|
1731
|
+
description: `${snapshot.lifecycle.length} retained runtime events`,
|
|
1732
|
+
children: /* @__PURE__ */ __name(() => renderLifecycleTimeline(snapshot.lifecycle, (section, next) => {
|
|
1733
|
+
onFocus(section, next);
|
|
1734
|
+
if (section === "components" && activeTab) activeTab.value = "tree";
|
|
1735
|
+
}), "children")
|
|
1736
|
+
}), "content") }
|
|
1737
|
+
],
|
|
1738
|
+
get value() {
|
|
1739
|
+
return activeTab?.value ?? "tree";
|
|
1740
|
+
},
|
|
1741
|
+
onChange: /* @__PURE__ */ __name((id) => {
|
|
1742
|
+
if (activeTab && isComponentsPanelTab(id)) activeTab.value = id;
|
|
1743
|
+
}, "onChange")
|
|
1744
|
+
});
|
|
1745
|
+
const root = createElement("div");
|
|
1746
|
+
setAttribute(root, "class", "vobs-devtools-components-tabs-wrap");
|
|
1747
|
+
insertBefore(root, tabs, null);
|
|
1748
|
+
return root;
|
|
1749
|
+
}
|
|
1750
|
+
__name(renderComponentsSection, "renderComponentsSection");
|
|
1751
|
+
function renderComponentTree(snapshot, query, selection, onFocus) {
|
|
1752
|
+
const componentTree = filterComponentTree(snapshot.tree, query);
|
|
1753
|
+
const list = createElement("div");
|
|
1754
|
+
setAttribute(list, "class", "vobs-devtools-list");
|
|
1755
|
+
for (const node of componentTree) insertBefore(list, renderComponentSummary(node, snapshot, selection, onFocus), null);
|
|
1756
|
+
if (componentTree.length === 0) appendMuted(list, query ? "No components match the search." : "No components recorded.");
|
|
1757
|
+
return createComponent(Card, {
|
|
1758
|
+
class: "vobs-devtools-component-tree-card",
|
|
1759
|
+
description: `Component tree ${snapshot.memory?.ownerCount ?? 0} active owners`,
|
|
1760
|
+
children: /* @__PURE__ */ __name(() => list, "children")
|
|
1761
|
+
});
|
|
1762
|
+
}
|
|
1763
|
+
__name(renderComponentTree, "renderComponentTree");
|
|
1764
|
+
function isComponentsPanelTab(value) {
|
|
1765
|
+
return value === "tree" || value === "lifecycle";
|
|
1766
|
+
}
|
|
1767
|
+
__name(isComponentsPanelTab, "isComponentsPanelTab");
|
|
1768
|
+
function renderUpdatesSection(snapshot, activeTab, query = "", selection = null, onFocus = () => void 0) {
|
|
1769
|
+
const tabs = createComponent(Tabs, {
|
|
1770
|
+
class: "vobs-devtools-router-tabs",
|
|
1771
|
+
variant: "filled",
|
|
1772
|
+
items: [
|
|
1773
|
+
{ id: "performance", label: "Performance", content: /* @__PURE__ */ __name(() => renderPerformanceMetrics(snapshot.metrics), "content") },
|
|
1774
|
+
{ id: "slow", label: "Slow items", content: /* @__PURE__ */ __name(() => renderSlowItems(snapshot.performanceEntries), "content") },
|
|
1775
|
+
{ id: "updates", label: `Updates${snapshot.updates.length ? ` (${snapshot.updates.length})` : ""}`, content: /* @__PURE__ */ __name(() => renderUpdatesList(snapshot, query, selection, onFocus), "content") }
|
|
1776
|
+
],
|
|
1777
|
+
get value() {
|
|
1778
|
+
return activeTab?.value ?? "updates";
|
|
1779
|
+
},
|
|
1780
|
+
onChange: /* @__PURE__ */ __name((id) => {
|
|
1781
|
+
if (activeTab && isUpdatesPanelTab(id)) activeTab.value = id;
|
|
1782
|
+
}, "onChange")
|
|
1783
|
+
});
|
|
1784
|
+
const root = createElement("div");
|
|
1785
|
+
setAttribute(root, "class", "vobs-devtools-updates-tabs-wrap");
|
|
1786
|
+
insertBefore(root, tabs, null);
|
|
1787
|
+
return root;
|
|
1788
|
+
}
|
|
1789
|
+
__name(renderUpdatesSection, "renderUpdatesSection");
|
|
1790
|
+
function isUpdatesPanelTab(value) {
|
|
1791
|
+
return value === "performance" || value === "slow" || value === "updates";
|
|
1792
|
+
}
|
|
1793
|
+
__name(isUpdatesPanelTab, "isUpdatesPanelTab");
|
|
1794
|
+
function renderUpdatesList(snapshot, query, selection, onFocus) {
|
|
1795
|
+
const list = createElement("div");
|
|
1796
|
+
setAttribute(list, "class", "vobs-devtools-list");
|
|
1797
|
+
for (const update of [...snapshot.updates].reverse().filter((update2) => matchesQuery(query, update2.signalName, update2.signalId, update2.status, formatValue(update2.previousValue), formatValue(update2.nextValue))).slice(0, 50)) {
|
|
1798
|
+
insertBefore(list, renderUpdateRow(update, snapshot.api, selection, onFocus), null);
|
|
1799
|
+
}
|
|
1800
|
+
if (snapshot.updates.length === 0) appendMuted(list, "Interact with the playground to record updates.");
|
|
1801
|
+
return createComponent(Card, {
|
|
1802
|
+
class: "vobs-devtools-updates-card",
|
|
1803
|
+
children: /* @__PURE__ */ __name(() => list, "children")
|
|
1804
|
+
});
|
|
1805
|
+
}
|
|
1806
|
+
__name(renderUpdatesList, "renderUpdatesList");
|
|
1807
|
+
function renderAdvancedSection(snapshot, activeSection, query = "") {
|
|
1808
|
+
const tabs = createComponent(Tabs, {
|
|
1809
|
+
class: "vobs-devtools-advanced-tabs",
|
|
1810
|
+
variant: "filled",
|
|
1811
|
+
items: [
|
|
1812
|
+
{ id: "signals", label: "Signals", content: /* @__PURE__ */ __name(() => renderSignalsInspector(snapshot, query), "content") },
|
|
1813
|
+
{ id: "effects", label: "Effects", content: /* @__PURE__ */ __name(() => renderEffectsInspector(snapshot, query), "content") }
|
|
1814
|
+
],
|
|
1815
|
+
get value() {
|
|
1816
|
+
return activeSection?.value ?? "signals";
|
|
1817
|
+
},
|
|
1818
|
+
onChange: /* @__PURE__ */ __name((id) => {
|
|
1819
|
+
if (activeSection) activeSection.value = id;
|
|
1820
|
+
}, "onChange")
|
|
1821
|
+
});
|
|
1822
|
+
const root = createElement("div");
|
|
1823
|
+
setAttribute(root, "class", "vobs-devtools-advanced");
|
|
1824
|
+
insertBefore(root, tabs, null);
|
|
1825
|
+
return root;
|
|
1826
|
+
}
|
|
1827
|
+
__name(renderAdvancedSection, "renderAdvancedSection");
|
|
1828
|
+
function renderSignalsInspector(snapshot, query) {
|
|
1829
|
+
const list = createElement("div");
|
|
1830
|
+
setAttribute(list, "class", "vobs-devtools-list");
|
|
1831
|
+
const signals = snapshot.signals.filter((signal) => matchesQuery(query, signal.name, signal.component, formatValue(signal.value))).slice(0, 50);
|
|
1832
|
+
for (const signal of signals) insertBefore(list, renderSignalInspector(signal, snapshot.api), null);
|
|
1833
|
+
if (signals.length === 0) appendMuted(list, query ? "No signals match the search." : "No signals recorded.");
|
|
1834
|
+
return list;
|
|
1835
|
+
}
|
|
1836
|
+
__name(renderSignalsInspector, "renderSignalsInspector");
|
|
1837
|
+
function renderEffectsInspector(snapshot, query) {
|
|
1838
|
+
const list = createElement("div");
|
|
1839
|
+
setAttribute(list, "class", "vobs-devtools-list");
|
|
1840
|
+
const effects = snapshot.effects.filter((effect2) => matchesQuery(query, effect2.name, effect2.component, effect2.id)).slice(0, 50);
|
|
1841
|
+
for (const effect2 of effects) insertBefore(list, renderEffectRow(effect2), null);
|
|
1842
|
+
if (effects.length === 0) appendMuted(list, query ? "No effects match the search." : "No effects recorded.");
|
|
1843
|
+
return list;
|
|
1844
|
+
}
|
|
1845
|
+
__name(renderEffectsInspector, "renderEffectsInspector");
|
|
1846
|
+
function renderPerformanceMetrics(metrics) {
|
|
1847
|
+
if (!metrics) {
|
|
1848
|
+
return createComponent(Card, { description: "Performance: Lightweight slow-path summary for the retained diagnostics.", children: /* @__PURE__ */ __name(() => {
|
|
1849
|
+
const root = createElement("div");
|
|
1850
|
+
appendMuted(root, "No performance data available.");
|
|
1851
|
+
return root;
|
|
1852
|
+
}, "children") });
|
|
1853
|
+
}
|
|
1854
|
+
const metricsGrid = createElement("div");
|
|
1855
|
+
setAttribute(metricsGrid, "class", "vobs-devtools-performance-metrics");
|
|
1856
|
+
appendMetric(metricsGrid, "Slow updates", metrics.slowUpdateCount);
|
|
1857
|
+
appendMetric(metricsGrid, "Slow effects", metrics.slowEffectCount);
|
|
1858
|
+
appendMetric(metricsGrid, "Slow requests", metrics.slowRequestCount);
|
|
1859
|
+
appendMetric(metricsGrid, "Max update", `${metrics.maxUpdateDuration.toFixed(2)} ms`);
|
|
1860
|
+
appendMetric(metricsGrid, "Max effect", `${metrics.maxEffectDuration.toFixed(2)} ms`);
|
|
1861
|
+
appendMetric(metricsGrid, "Max request", `${metrics.maxRequestDuration.toFixed(2)} ms`);
|
|
1862
|
+
return createComponent(Card, {
|
|
1863
|
+
class: "vobs-devtools-performance-card",
|
|
1864
|
+
description: "Lightweight slow-path summary for the retained diagnostics.",
|
|
1865
|
+
children: /* @__PURE__ */ __name(() => metricsGrid, "children")
|
|
1866
|
+
});
|
|
1867
|
+
}
|
|
1868
|
+
__name(renderPerformanceMetrics, "renderPerformanceMetrics");
|
|
1869
|
+
function renderSlowItems(entries) {
|
|
1870
|
+
const slowEntries = entries.filter((entry) => entry.duration >= 16).slice(0, 8);
|
|
1871
|
+
const slowList = createElement("div");
|
|
1872
|
+
setAttribute(slowList, "class", "vobs-devtools-performance-slow-list");
|
|
1873
|
+
for (const entry of slowEntries) {
|
|
1874
|
+
const item = createElement("div");
|
|
1875
|
+
setAttribute(item, "class", "vobs-devtools-performance-slow-item");
|
|
1876
|
+
appendText(item, entry.kind, "vobs-devtools-muted");
|
|
1877
|
+
appendText(item, formatPerformanceLabel(entry), "vobs-devtools-list__name");
|
|
1878
|
+
appendText(item, `${entry.duration.toFixed(2)} ms`, "vobs-devtools-code");
|
|
1879
|
+
insertBefore(slowList, item, null);
|
|
1880
|
+
}
|
|
1881
|
+
if (slowEntries.length === 0) appendMuted(slowList, "No slow items recorded.");
|
|
1882
|
+
return createComponent(Card, {
|
|
1883
|
+
class: "vobs-devtools-performance-slow-card",
|
|
1884
|
+
description: slowEntries.length ? `${slowEntries.length} retained item${slowEntries.length === 1 ? "" : "s"} at or above 16 ms.` : void 0,
|
|
1885
|
+
children: /* @__PURE__ */ __name(() => slowList, "children")
|
|
1886
|
+
});
|
|
1887
|
+
}
|
|
1888
|
+
__name(renderSlowItems, "renderSlowItems");
|
|
1889
|
+
function formatPerformanceLabel(entry) {
|
|
1890
|
+
if (entry.kind === "request") return entry.label;
|
|
1891
|
+
const formatted = formatDebugLocation(entry.label);
|
|
1892
|
+
const openParen = formatted.indexOf("(");
|
|
1893
|
+
const closeParen = openParen >= 0 ? formatted.indexOf(")", openParen) : -1;
|
|
1894
|
+
if (openParen < 0 || closeParen < 0) return stripDebugLocation(entry.label);
|
|
1895
|
+
const componentName = formatted.slice(0, openParen).trim();
|
|
1896
|
+
const source = formatted.slice(openParen + 1, closeParen);
|
|
1897
|
+
const fileName = source.split("/").pop() ?? source;
|
|
1898
|
+
const suffix = formatted.slice(closeParen + 1).trim();
|
|
1899
|
+
return [componentName, fileName, suffix].filter(Boolean).join(" ");
|
|
1900
|
+
}
|
|
1901
|
+
__name(formatPerformanceLabel, "formatPerformanceLabel");
|
|
1902
|
+
function appendMetric(parent, label, value) {
|
|
1903
|
+
const row = createElement("div");
|
|
1904
|
+
setAttribute(row, "class", "vobs-devtools-performance-item");
|
|
1905
|
+
appendText(row, label, "vobs-devtools-muted");
|
|
1906
|
+
appendText(row, String(value), "vobs-devtools-list__name");
|
|
1907
|
+
insertBefore(parent, row, null);
|
|
1908
|
+
}
|
|
1909
|
+
__name(appendMetric, "appendMetric");
|
|
1910
|
+
function renderRouterSection(router, activeRouterTab, activeRouteView) {
|
|
1911
|
+
if (!router) return createComponent(Alert, { tone: "warning", title: "Router unavailable", description: "Pass a Router instance to inspect route activity." });
|
|
1912
|
+
const devtools = router.devtools;
|
|
1913
|
+
const root = createElement("div");
|
|
1914
|
+
setAttribute(root, "class", "vobs-devtools-router");
|
|
1915
|
+
const current = devtools.getCurrentRoute();
|
|
1916
|
+
const state2 = devtools.getNavigationState();
|
|
1917
|
+
const metrics = devtools.getPerformanceMetrics();
|
|
1918
|
+
const activeRequests = devtools.getDataRequests().filter((request) => request.route === current.fullPath || request.key.startsWith(`${current.fullPath}#`));
|
|
1919
|
+
const activeErrors = devtools.getErrors().filter((error) => error.route === current.fullPath);
|
|
1920
|
+
const toolbar = createElement("div");
|
|
1921
|
+
setAttribute(toolbar, "class", "vobs-devtools-panel__toolbar");
|
|
1922
|
+
insertBefore(toolbar, createComponent(Button, { variant: "secondary", icon: createComponent(Icon, { name: "refresh" }), children: /* @__PURE__ */ __name(() => "Revalidate current route", "children"), onClick: /* @__PURE__ */ __name(() => {
|
|
1923
|
+
void devtools.revalidate(current.fullPath);
|
|
1924
|
+
}, "onClick") }), null);
|
|
1925
|
+
const tabs = createComponent(Tabs, {
|
|
1926
|
+
class: "vobs-devtools-router-tabs",
|
|
1927
|
+
variant: "filled",
|
|
1928
|
+
items: [
|
|
1929
|
+
{ id: "context", label: "Context", content: /* @__PURE__ */ __name(() => createRouterContextPanel(current, state2), "content") },
|
|
1930
|
+
{ id: "requests", label: `Requests${activeRequests.length ? ` (${activeRequests.length})` : ""}`, content: /* @__PURE__ */ __name(() => createComponent(Card, { title: `Data requests for ${current.path}`, description: "Loader, action and fetcher traces for the active route.", children: /* @__PURE__ */ __name(() => renderDataRequests(activeRequests), "children") }), "content") },
|
|
1931
|
+
{ id: "errors", label: `Errors${activeErrors.length ? ` (${activeErrors.length})` : ""}`, content: /* @__PURE__ */ __name(() => createComponent(Card, { title: `Errors for ${current.path}`, description: `${activeErrors.length} errors captured for the active route.`, children: /* @__PURE__ */ __name(() => renderRouterErrors(activeErrors), "children") }), "content") },
|
|
1932
|
+
{ id: "history", label: "History", content: /* @__PURE__ */ __name(() => createComponent(Card, { title: "Navigation history", description: `${metrics.navigationCount} recorded navigations \xB7 ${metrics.averageNavigationDuration.toFixed(2)} ms average`, children: /* @__PURE__ */ __name(() => renderNavigationHistory(devtools.getNavigationHistory(), router), "children") }), "content") },
|
|
1933
|
+
{ id: "routes", label: "Route map", content: /* @__PURE__ */ __name(() => createComponent(Card, {
|
|
1934
|
+
title: "Route map",
|
|
1935
|
+
description: "All registered routes and their source locations.",
|
|
1936
|
+
children: /* @__PURE__ */ __name(() => renderRouteMap(devtools.getRouteTree(), router, activeRouteView), "children")
|
|
1937
|
+
}), "content") }
|
|
1938
|
+
],
|
|
1939
|
+
get value() {
|
|
1940
|
+
return activeRouterTab?.value ?? "context";
|
|
1941
|
+
},
|
|
1942
|
+
onChange: /* @__PURE__ */ __name((id) => {
|
|
1943
|
+
if (activeRouterTab) activeRouterTab.value = id;
|
|
1944
|
+
}, "onChange")
|
|
1945
|
+
});
|
|
1946
|
+
const tabsWrap = createElement("div");
|
|
1947
|
+
setAttribute(tabsWrap, "class", "vobs-devtools-router-tabs-wrap");
|
|
1948
|
+
insertBefore(tabsWrap, tabs, null);
|
|
1949
|
+
insertBefore(tabsWrap, toolbar, null);
|
|
1950
|
+
insertBefore(root, tabsWrap, null);
|
|
1951
|
+
return root;
|
|
1952
|
+
}
|
|
1953
|
+
__name(renderRouterSection, "renderRouterSection");
|
|
1954
|
+
function createRouterContextPanel(current, state2) {
|
|
1955
|
+
return createFragment((parent, anchor) => {
|
|
1956
|
+
insertBefore(parent, createComponent(Card, { title: "Active route", children: /* @__PURE__ */ __name(() => renderRouterLocation(current, state2), "children") }), anchor);
|
|
1957
|
+
insertBefore(parent, createComponent(Card, { title: "Matched route structure", children: /* @__PURE__ */ __name(() => renderMatchedRoutes(current.matched), "children") }), anchor);
|
|
1958
|
+
});
|
|
1959
|
+
}
|
|
1960
|
+
__name(createRouterContextPanel, "createRouterContextPanel");
|
|
1961
|
+
function renderDataRequests(requests) {
|
|
1962
|
+
const root = createElement("div");
|
|
1963
|
+
setAttribute(root, "class", "vobs-devtools-list");
|
|
1964
|
+
for (const request of [...requests].reverse().slice(0, 30)) {
|
|
1965
|
+
const row = createElement("details");
|
|
1966
|
+
setAttribute(row, "class", "vobs-devtools-list__row");
|
|
1967
|
+
const summary = createElement("summary");
|
|
1968
|
+
appendText(summary, `${request.kind} \xB7 ${request.key}`, "vobs-devtools-list__name");
|
|
1969
|
+
insertBefore(summary, createComponent(Tag, { tone: request.status === "success" ? "success" : request.status === "error" ? "danger" : "warning", children: /* @__PURE__ */ __name(() => request.status, "children") }), null);
|
|
1970
|
+
appendText(summary, request.duration === void 0 ? "running" : `${request.duration.toFixed(2)} ms`);
|
|
1971
|
+
insertBefore(row, summary, null);
|
|
1972
|
+
if (request.error) appendText(row, request.error);
|
|
1973
|
+
if (request.status === "success" && request.result !== void 0) insertBefore(row, renderInspectableValue("Result", request.result), null);
|
|
1974
|
+
insertBefore(root, row, null);
|
|
1975
|
+
}
|
|
1976
|
+
if (requests.length === 0) appendMuted(root, "No data requests recorded.");
|
|
1977
|
+
return root;
|
|
1978
|
+
}
|
|
1979
|
+
__name(renderDataRequests, "renderDataRequests");
|
|
1980
|
+
function renderRouterErrors(errors) {
|
|
1981
|
+
const root = createElement("div");
|
|
1982
|
+
setAttribute(root, "class", "vobs-devtools-list");
|
|
1983
|
+
for (const error of [...errors].reverse().slice(0, 30)) {
|
|
1984
|
+
const row = createElement("details");
|
|
1985
|
+
setAttribute(row, "class", "vobs-devtools-list__row vobs-devtools-error-row");
|
|
1986
|
+
const summary = createElement("summary");
|
|
1987
|
+
appendText(summary, `${error.phase} \xB7 ${error.route}`, "vobs-devtools-list__name");
|
|
1988
|
+
appendText(summary, error.message);
|
|
1989
|
+
insertBefore(row, summary, null);
|
|
1990
|
+
if (error.stack) appendText(row, error.stack, "vobs-devtools-code");
|
|
1991
|
+
insertBefore(root, row, null);
|
|
1992
|
+
}
|
|
1993
|
+
if (errors.length === 0) appendMuted(root, "No route errors recorded.");
|
|
1994
|
+
return root;
|
|
1995
|
+
}
|
|
1996
|
+
__name(renderRouterErrors, "renderRouterErrors");
|
|
1997
|
+
function renderRouterLocation(route, state2) {
|
|
1998
|
+
const root = createElement("div");
|
|
1999
|
+
setAttribute(root, "class", "vobs-devtools-list");
|
|
2000
|
+
const statusRow = createElement("div");
|
|
2001
|
+
setAttribute(statusRow, "class", "vobs-devtools-list__row");
|
|
2002
|
+
appendText(statusRow, route.fullPath, "vobs-devtools-list__name");
|
|
2003
|
+
insertBefore(statusRow, createComponent(Tag, { tone: state2.status === "error" ? "danger" : state2.status === "loading" ? "warning" : "success", children: /* @__PURE__ */ __name(() => state2.status, "children") }), null);
|
|
2004
|
+
if (state2.status === "loading") appendText(statusRow, `to ${state2.to}`);
|
|
2005
|
+
if (state2.error) appendText(statusRow, state2.error);
|
|
2006
|
+
insertBefore(root, statusRow, null);
|
|
2007
|
+
insertBefore(root, renderInspectableValue("Params", route.params), null);
|
|
2008
|
+
insertBefore(root, renderInspectableValue("Query", route.query), null);
|
|
2009
|
+
insertBefore(root, renderInspectableValue("Meta", route.meta), null);
|
|
2010
|
+
appendText(root, `outlet ${route.matched.map((record) => record.path ?? "(layout)").join(" > ")}`);
|
|
2011
|
+
return root;
|
|
2012
|
+
}
|
|
2013
|
+
__name(renderRouterLocation, "renderRouterLocation");
|
|
2014
|
+
function renderMatchedRoutes(records) {
|
|
2015
|
+
const root = createElement("div");
|
|
2016
|
+
setAttribute(root, "class", "vobs-devtools-route-tree");
|
|
2017
|
+
records.forEach((record, index) => {
|
|
2018
|
+
const row = createElement("div");
|
|
2019
|
+
setAttribute(row, "class", "vobs-devtools-route-node");
|
|
2020
|
+
setAttribute(row, "style", `--route-depth: ${index}`);
|
|
2021
|
+
appendText(row, record.path ?? "(layout)", "vobs-devtools-list__name");
|
|
2022
|
+
appendText(row, routeComponentName(record));
|
|
2023
|
+
if (record.source) appendText(row, record.source, "vobs-devtools-code");
|
|
2024
|
+
if (record.loader) insertBefore(row, createComponent(Tag, { tone: "neutral-strong", children: /* @__PURE__ */ __name(() => "loader", "children") }), null);
|
|
2025
|
+
if (record.action) insertBefore(row, createComponent(Tag, { tone: "neutral-strong", children: /* @__PURE__ */ __name(() => "action", "children") }), null);
|
|
2026
|
+
insertBefore(root, row, null);
|
|
2027
|
+
});
|
|
2028
|
+
if (records.length === 0) appendMuted(root, "No matched route records.");
|
|
2029
|
+
return root;
|
|
2030
|
+
}
|
|
2031
|
+
__name(renderMatchedRoutes, "renderMatchedRoutes");
|
|
2032
|
+
function renderRouteMap(nodes, router, activeRouteView) {
|
|
2033
|
+
const tree = createElement("div");
|
|
2034
|
+
setAttribute(tree, "class", "vobs-devtools-route-tree");
|
|
2035
|
+
const controls = createElement("div");
|
|
2036
|
+
setAttribute(controls, "class", "vobs-devtools-route-view-toggle");
|
|
2037
|
+
for (const mode of ["tree", "list"]) {
|
|
2038
|
+
const button = createElement("button");
|
|
2039
|
+
setAttribute(button, "class", `vobs-devtools-control${(activeRouteView?.value ?? "tree") === mode ? " is-active" : ""}`);
|
|
2040
|
+
setAttribute(button, "type", "button");
|
|
2041
|
+
setAttribute(button, "aria-pressed", (activeRouteView?.value ?? "tree") === mode ? "true" : "false");
|
|
2042
|
+
insertBefore(button, createText(mode === "tree" ? "Tree" : "List"), null);
|
|
2043
|
+
button.addEventListener("click", () => {
|
|
2044
|
+
if (activeRouteView) activeRouteView.value = mode;
|
|
2045
|
+
});
|
|
2046
|
+
insertBefore(controls, button, null);
|
|
2047
|
+
}
|
|
2048
|
+
insertBefore(tree, controls, null);
|
|
2049
|
+
const currentPath = router.currentRoute.value.path;
|
|
2050
|
+
if ((activeRouteView?.value ?? "tree") === "list") {
|
|
2051
|
+
for (const node of flattenRouteNodes(nodes)) appendRouteConfigNode(tree, node, 0, router, currentPath);
|
|
2052
|
+
} else {
|
|
2053
|
+
for (const node of nodes) appendRouteConfigNode(tree, node, 0, router, currentPath);
|
|
2054
|
+
}
|
|
2055
|
+
return tree;
|
|
2056
|
+
}
|
|
2057
|
+
__name(renderRouteMap, "renderRouteMap");
|
|
2058
|
+
function flattenRouteNodes(nodes) {
|
|
2059
|
+
const result = [];
|
|
2060
|
+
const visit = /* @__PURE__ */ __name((node) => {
|
|
2061
|
+
result.push({ ...node, children: [] });
|
|
2062
|
+
for (const child of node.children) visit(child);
|
|
2063
|
+
}, "visit");
|
|
2064
|
+
for (const node of nodes) visit(node);
|
|
2065
|
+
return result;
|
|
2066
|
+
}
|
|
2067
|
+
__name(flattenRouteNodes, "flattenRouteNodes");
|
|
2068
|
+
function appendRouteConfigNode(parent, node, depth, router, currentPath) {
|
|
2069
|
+
const concrete = node.children.length === 0 && !node.path.includes(":") && !node.path.includes("*");
|
|
2070
|
+
const row = createElement(concrete ? "button" : "div");
|
|
2071
|
+
setAttribute(row, "class", `vobs-devtools-route-node${concrete && node.path === currentPath ? " is-active" : ""}`);
|
|
2072
|
+
setAttribute(row, "style", `--route-depth: ${depth}`);
|
|
2073
|
+
appendText(row, node.path, "vobs-devtools-list__name");
|
|
2074
|
+
appendText(row, node.component);
|
|
2075
|
+
if (node.source) appendText(row, node.source, "vobs-devtools-code");
|
|
2076
|
+
if (concrete) {
|
|
2077
|
+
setAttribute(row, "type", "button");
|
|
2078
|
+
setAttribute(row, "title", `Navigate to ${node.path}`);
|
|
2079
|
+
row.addEventListener("click", () => {
|
|
2080
|
+
void router.push(node.path);
|
|
2081
|
+
});
|
|
2082
|
+
}
|
|
2083
|
+
insertBefore(parent, row, null);
|
|
2084
|
+
for (const child of node.children) appendRouteConfigNode(parent, child, depth + 1, router, currentPath);
|
|
2085
|
+
}
|
|
2086
|
+
__name(appendRouteConfigNode, "appendRouteConfigNode");
|
|
2087
|
+
function routeComponentName(record) {
|
|
2088
|
+
const definition = record.component;
|
|
2089
|
+
if (!definition) return "Route";
|
|
2090
|
+
if (typeof definition === "function") return definition.name || "Anonymous";
|
|
2091
|
+
return "lazy(...)";
|
|
2092
|
+
}
|
|
2093
|
+
__name(routeComponentName, "routeComponentName");
|
|
2094
|
+
function renderNavigationHistory(history, router) {
|
|
2095
|
+
const root = createElement("div");
|
|
2096
|
+
setAttribute(root, "class", "vobs-devtools-list");
|
|
2097
|
+
for (const trace of [...history].reverse().slice(0, 30)) {
|
|
2098
|
+
const row = createElement("button");
|
|
2099
|
+
setAttribute(row, "class", "vobs-devtools-list__row");
|
|
2100
|
+
setAttribute(row, "type", "button");
|
|
2101
|
+
setAttribute(row, "title", `Replay ${trace.to}`);
|
|
2102
|
+
appendText(row, `${trace.from} \u2192 ${trace.to}`, "vobs-devtools-list__name");
|
|
2103
|
+
insertBefore(row, createComponent(Tag, { tone: trace.status === "success" ? "success" : trace.status === "error" ? "danger" : "warning", children: /* @__PURE__ */ __name(() => trace.status, "children") }), null);
|
|
2104
|
+
appendText(row, `${trace.duration.toFixed(2)} ms \xB7 ${trace.source}`);
|
|
2105
|
+
row.addEventListener("click", () => {
|
|
2106
|
+
void router.push(trace.to);
|
|
2107
|
+
});
|
|
2108
|
+
insertBefore(root, row, null);
|
|
2109
|
+
}
|
|
2110
|
+
if (history.length === 0) appendMuted(root, "No navigation history recorded.");
|
|
2111
|
+
return root;
|
|
2112
|
+
}
|
|
2113
|
+
__name(renderNavigationHistory, "renderNavigationHistory");
|
|
2114
|
+
function appendMuted(parent, value) {
|
|
2115
|
+
const node = createElement("span");
|
|
2116
|
+
setAttribute(node, "class", "vobs-devtools-muted");
|
|
2117
|
+
insertBefore(node, createText(value), null);
|
|
2118
|
+
insertBefore(parent, node, null);
|
|
2119
|
+
}
|
|
2120
|
+
__name(appendMuted, "appendMuted");
|
|
2121
|
+
function renderSignalInspector(signal, api) {
|
|
2122
|
+
const row = createElement("details");
|
|
2123
|
+
setAttribute(row, "class", "vobs-devtools-list__row vobs-devtools-signal-row");
|
|
2124
|
+
const summary = createElement("summary");
|
|
2125
|
+
appendText(summary, displaySignalName(signal), "vobs-devtools-list__name");
|
|
2126
|
+
appendText(summary, previewValue(signal.value), "vobs-devtools-code");
|
|
2127
|
+
insertBefore(summary, createComponent(Tag, { tone: "neutral-strong", children: /* @__PURE__ */ __name(() => `${signal.subscribers} subscribers`, "children") }), null);
|
|
2128
|
+
insertBefore(row, summary, null);
|
|
2129
|
+
if (!api) return row;
|
|
2130
|
+
const dependencies = api.getDependencies(signal.id);
|
|
2131
|
+
const dependents = api.getDependents(signal.id);
|
|
2132
|
+
insertBefore(row, renderInspectableValue("Current value", signal.value), null);
|
|
2133
|
+
appendText(row, `${dependencies.length} dependencies \xB7 ${dependents.length} dependents`, "vobs-devtools-muted");
|
|
2134
|
+
if (api.canMutate() && signal.kind !== "memo") insertBefore(row, renderSignalMutationControl(signal, api), null);
|
|
2135
|
+
return row;
|
|
2136
|
+
}
|
|
2137
|
+
__name(renderSignalInspector, "renderSignalInspector");
|
|
2138
|
+
function renderSignalMutationControl(signal, api) {
|
|
2139
|
+
const root = createElement("div");
|
|
2140
|
+
setAttribute(root, "class", "vobs-devtools-mutation-control");
|
|
2141
|
+
appendText(root, "Debug-only value edit (may trigger effects and requests).", "vobs-devtools-muted");
|
|
2142
|
+
const input = createElement("input");
|
|
2143
|
+
setAttribute(input, "class", "vobs-devtools-search");
|
|
2144
|
+
setAttribute(input, "type", "text");
|
|
2145
|
+
setAttribute(input, "aria-label", `Edit ${signal.name}`);
|
|
2146
|
+
setProperty(input, "value", formatValue(signal.value));
|
|
2147
|
+
const button = createElement("button");
|
|
2148
|
+
setAttribute(button, "class", "vobs-devtools-control");
|
|
2149
|
+
setAttribute(button, "type", "button");
|
|
2150
|
+
insertBefore(button, createText("Apply debug value"), null);
|
|
2151
|
+
button.addEventListener("click", (event) => {
|
|
2152
|
+
event.stopPropagation();
|
|
2153
|
+
const raw = input.value;
|
|
2154
|
+
let value = raw;
|
|
2155
|
+
try {
|
|
2156
|
+
value = JSON.parse(raw);
|
|
2157
|
+
} catch {
|
|
2158
|
+
}
|
|
2159
|
+
api.setSignalValue(signal.id, value);
|
|
2160
|
+
});
|
|
2161
|
+
insertBefore(root, input, null);
|
|
2162
|
+
insertBefore(root, button, null);
|
|
2163
|
+
return root;
|
|
2164
|
+
}
|
|
2165
|
+
__name(renderSignalMutationControl, "renderSignalMutationControl");
|
|
2166
|
+
function renderEffectRow(effect2) {
|
|
2167
|
+
const row = createElement("details");
|
|
2168
|
+
setAttribute(row, "class", "vobs-devtools-list__row");
|
|
2169
|
+
const summary = createElement("summary");
|
|
2170
|
+
const component = formatDebugLocation(effect2.component);
|
|
2171
|
+
appendText(summary, effect2.name || `${debugComponentName(component)} effect`, "vobs-devtools-list__name");
|
|
2172
|
+
appendText(summary, formatDebugSource(component));
|
|
2173
|
+
insertBefore(summary, createComponent(Tag, { tone: effect2.status === "success" || effect2.status === "idle" ? "success" : effect2.status === "error" ? "danger" : "warning", children: /* @__PURE__ */ __name(() => effect2.status, "children") }), null);
|
|
2174
|
+
appendText(summary, `${effect2.executionCount} runs`);
|
|
2175
|
+
insertBefore(row, summary, null);
|
|
2176
|
+
appendText(row, `${effect2.dependencies.length} dependencies`, "vobs-devtools-muted");
|
|
2177
|
+
if (effect2.lastExecutionTime > 0) appendText(row, `last execution ${effect2.lastDuration?.toFixed(2) ?? "0.00"} ms \xB7 ${effect2.lastRunStatus ?? "unknown"} \xB7 ${effect2.lastDomUpdates ?? 0} DOM updates`, "vobs-devtools-muted");
|
|
2178
|
+
if (effect2.lastUpdateId) appendText(row, `last update ${effect2.lastUpdateId}`, "vobs-devtools-code");
|
|
2179
|
+
if (effect2.lastError) appendText(row, `${effect2.lastError.name}: ${effect2.lastError.message}`, "vobs-devtools-error");
|
|
2180
|
+
return row;
|
|
2181
|
+
}
|
|
2182
|
+
__name(renderEffectRow, "renderEffectRow");
|
|
2183
|
+
function renderUpdateRow(update, api, selection = null, onFocus = () => void 0) {
|
|
2184
|
+
const row = createElement("details");
|
|
2185
|
+
const selected = selection?.type === "update" && selection.id === update.id;
|
|
2186
|
+
setAttribute(row, "class", `vobs-devtools-update-row${selected ? " is-selected" : ""}`);
|
|
2187
|
+
if (selected) setProperty(row, "open", true);
|
|
2188
|
+
const summary = createElement("summary");
|
|
2189
|
+
summary.addEventListener("click", () => onFocus("updates", { type: "update", id: update.id }));
|
|
2190
|
+
const signal = api?.getSignal(update.signalId);
|
|
2191
|
+
appendText(summary, signal ? displaySignalName(signal) : displayDebugName(update.signalName), "vobs-devtools-list__name");
|
|
2192
|
+
appendText(summary, formatDebugSource(signal?.component ?? "unknown"), "vobs-devtools-update-row__source");
|
|
2193
|
+
appendText(summary, `${update.duration.toFixed(2)} ms`);
|
|
2194
|
+
insertBefore(summary, createComponent(Tag, { tone: update.duration >= 16 ? "warning" : "neutral-strong", children: /* @__PURE__ */ __name(() => `${update.effects.length} effects`, "children") }), null);
|
|
2195
|
+
insertBefore(row, summary, null);
|
|
2196
|
+
insertBefore(row, renderValuePair("Value changed", update.previousValue, update.nextValue), null);
|
|
2197
|
+
appendText(row, `status ${update.status} \xB7 ${update.affectedSignals.length} signals \xB7 ${update.affectedEffects.length} effects`, "vobs-devtools-muted");
|
|
2198
|
+
if (update.error) appendText(row, `${update.error.name}: ${update.error.message}`, "vobs-devtools-error");
|
|
2199
|
+
if (update.effects.length === 0) appendText(row, "No effects executed.", "vobs-devtools-muted");
|
|
2200
|
+
for (const effect2 of update.effects) {
|
|
2201
|
+
insertBefore(row, renderEffectExecution(effect2), null);
|
|
2202
|
+
if (effect2.error) appendText(row, `${effect2.error.name}: ${effect2.error.message}`, "vobs-devtools-error");
|
|
2203
|
+
}
|
|
2204
|
+
for (const domUpdate of update.domUpdates) {
|
|
2205
|
+
const operation = domUpdate.key ? `${domUpdate.operation}.${domUpdate.key}` : domUpdate.operation;
|
|
2206
|
+
const mutation = createElement("div");
|
|
2207
|
+
setAttribute(mutation, "class", "vobs-devtools-dom-update");
|
|
2208
|
+
appendText(mutation, operation, "vobs-devtools-list__name");
|
|
2209
|
+
appendText(mutation, domUpdate.target, "vobs-devtools-muted");
|
|
2210
|
+
if (domUpdate.previousValue !== void 0 || domUpdate.nextValue !== void 0) {
|
|
2211
|
+
insertBefore(mutation, renderValuePair("", domUpdate.previousValue, domUpdate.nextValue), null);
|
|
2212
|
+
}
|
|
2213
|
+
insertBefore(row, mutation, null);
|
|
2214
|
+
}
|
|
2215
|
+
return row;
|
|
2216
|
+
}
|
|
2217
|
+
__name(renderUpdateRow, "renderUpdateRow");
|
|
2218
|
+
function renderEffectExecution(effect2) {
|
|
2219
|
+
const root = createElement("div");
|
|
2220
|
+
setAttribute(root, "class", "vobs-devtools-effect-execution");
|
|
2221
|
+
appendText(root, effect2.effectId, "vobs-devtools-code");
|
|
2222
|
+
appendText(root, `${formatDebugSource(effect2.component)} \xB7 ${effect2.duration.toFixed(2)} ms \xB7 ${effect2.domUpdates} DOM updates \xB7 ${effect2.status ?? "success"}`);
|
|
2223
|
+
return root;
|
|
2224
|
+
}
|
|
2225
|
+
__name(renderEffectExecution, "renderEffectExecution");
|
|
2226
|
+
function appendUpdateLinks(parent, ids, onFocus) {
|
|
2227
|
+
if (ids.length === 0) {
|
|
2228
|
+
appendText(parent, " none", "vobs-devtools-muted");
|
|
2229
|
+
return;
|
|
2230
|
+
}
|
|
2231
|
+
for (const id of ids) {
|
|
2232
|
+
const button = createElement("button");
|
|
2233
|
+
setAttribute(button, "class", "vobs-devtools-link");
|
|
2234
|
+
setAttribute(button, "type", "button");
|
|
2235
|
+
button.addEventListener("click", (event) => {
|
|
2236
|
+
event.stopPropagation();
|
|
2237
|
+
onFocus("updates", { type: "update", id });
|
|
2238
|
+
});
|
|
2239
|
+
insertBefore(button, createText(id), null);
|
|
2240
|
+
insertBefore(parent, button, null);
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
__name(appendUpdateLinks, "appendUpdateLinks");
|
|
2244
|
+
function renderLifecycleTimeline(events, onFocus) {
|
|
2245
|
+
const root = createElement("div");
|
|
2246
|
+
setAttribute(root, "class", "vobs-devtools-lifecycle-list");
|
|
2247
|
+
for (const event of [...events].reverse().slice(0, 40)) {
|
|
2248
|
+
const selection = lifecycleSelection(event);
|
|
2249
|
+
const row = createElement(selection?.type === "component" ? "button" : "div");
|
|
2250
|
+
setAttribute(row, "class", "vobs-devtools-lifecycle-row");
|
|
2251
|
+
if (selection?.type === "component") setAttribute(row, "type", "button");
|
|
2252
|
+
appendText(row, event.type, "vobs-devtools-list__name");
|
|
2253
|
+
appendText(row, event.name ?? event.targetId);
|
|
2254
|
+
appendText(row, event.status ?? "", "vobs-devtools-muted");
|
|
2255
|
+
if (selection?.type === "component") row.addEventListener("click", () => onFocus("components", selection));
|
|
2256
|
+
insertBefore(root, row, null);
|
|
2257
|
+
}
|
|
2258
|
+
if (events.length === 0) appendMuted(root, "No lifecycle events recorded.");
|
|
2259
|
+
return root;
|
|
2260
|
+
}
|
|
2261
|
+
__name(renderLifecycleTimeline, "renderLifecycleTimeline");
|
|
2262
|
+
function renderUnifiedNetworkRequests(requests, routerRequests, query, selection, onFocus, networkSelection, sourceFilter, statusFilter, detailTab, api, queryState, http, testerOpen, testerRevision, testerRun, testerDraft, currentRoute, testerTab) {
|
|
2263
|
+
const root = createElement("div");
|
|
2264
|
+
setAttribute(root, "class", "vobs-devtools-network-inspector");
|
|
2265
|
+
const activeSource = sourceFilter?.value ?? "all";
|
|
2266
|
+
const activeStatus = statusFilter?.value ?? "all";
|
|
2267
|
+
const entries = [
|
|
2268
|
+
...requests.map((request) => ({
|
|
2269
|
+
key: `http:${request.id}`,
|
|
2270
|
+
source: request.source === "ssr" ? "ssr" : "http",
|
|
2271
|
+
method: request.method,
|
|
2272
|
+
url: request.url,
|
|
2273
|
+
status: request.status,
|
|
2274
|
+
duration: request.duration,
|
|
2275
|
+
startedAt: request.startedAt,
|
|
2276
|
+
endedAt: request.endedAt,
|
|
2277
|
+
request
|
|
2278
|
+
})),
|
|
2279
|
+
...routerRequests.map((request) => ({
|
|
2280
|
+
key: `router:${request.id}`,
|
|
2281
|
+
source: "router",
|
|
2282
|
+
method: request.kind,
|
|
2283
|
+
url: request.key,
|
|
2284
|
+
status: request.status,
|
|
2285
|
+
duration: request.duration,
|
|
2286
|
+
startedAt: request.startedAt,
|
|
2287
|
+
endedAt: request.endedAt,
|
|
2288
|
+
routerRequest: request
|
|
2289
|
+
}))
|
|
2290
|
+
].filter((entry) => (activeSource === "all" || entry.source === activeSource) && (activeStatus === "all" || entry.status === activeStatus) && matchesQuery(query, entry.method, entry.url, entry.status, entry.source, entry.request?.responseStatus, entry.request?.route, entry.routerRequest?.route)).sort((left, right) => (right.startedAt ?? 0) - (left.startedAt ?? 0));
|
|
2291
|
+
const selectedKey = (selection?.type === "request" ? `http:${selection.id}` : networkSelection?.value) ?? entries[0]?.key;
|
|
2292
|
+
const selected = entries.find((entry) => entry.key === selectedKey) ?? entries[0];
|
|
2293
|
+
const controls = createElement("div");
|
|
2294
|
+
setAttribute(controls, "class", "vobs-devtools-network-toolbar");
|
|
2295
|
+
appendText(controls, "Search", "vobs-devtools-network-toolbar__label");
|
|
2296
|
+
const search = createElement("input");
|
|
2297
|
+
setAttribute(search, "class", "vobs-devtools-search vobs-devtools-network-toolbar__search");
|
|
2298
|
+
setAttribute(search, "type", "search");
|
|
2299
|
+
setAttribute(search, "placeholder", "Search requests");
|
|
2300
|
+
setProperty(search, "value", query);
|
|
2301
|
+
search.addEventListener("change", () => {
|
|
2302
|
+
if (queryState) queryState.value = search.value;
|
|
2303
|
+
});
|
|
2304
|
+
insertBefore(controls, search, null);
|
|
2305
|
+
insertBefore(controls, createNetworkFilterSelect("Source", activeSource, [
|
|
2306
|
+
["all", "All sources"],
|
|
2307
|
+
["http", "HTTP"],
|
|
2308
|
+
["router", "Router"],
|
|
2309
|
+
["ssr", "SSR"]
|
|
2310
|
+
], (value) => {
|
|
2311
|
+
if (sourceFilter) sourceFilter.value = value;
|
|
2312
|
+
}), null);
|
|
2313
|
+
insertBefore(controls, createNetworkFilterSelect("Status", activeStatus, [
|
|
2314
|
+
["all", "All statuses"],
|
|
2315
|
+
["loading", "Loading"],
|
|
2316
|
+
["success", "Success"],
|
|
2317
|
+
["error", "Error"],
|
|
2318
|
+
["cancelled", "Cancelled"]
|
|
2319
|
+
], (value) => {
|
|
2320
|
+
if (statusFilter) statusFilter.value = value;
|
|
2321
|
+
}), null);
|
|
2322
|
+
if (api) insertBefore(controls, createComponent(Button, {
|
|
2323
|
+
variant: "ghost",
|
|
2324
|
+
children: /* @__PURE__ */ __name(() => "Clear", "children"),
|
|
2325
|
+
onClick: /* @__PURE__ */ __name(() => api.clearNetworkRequests(), "onClick")
|
|
2326
|
+
}), null);
|
|
2327
|
+
if (testerOpen && testerDraft) insertBefore(controls, createComponent(Button, {
|
|
2328
|
+
variant: "ghost",
|
|
2329
|
+
iconOnly: true,
|
|
2330
|
+
icon: createComponent(Icon, { name: "settings" }),
|
|
2331
|
+
"aria-label": "Open Request Tester",
|
|
2332
|
+
title: "Open Request Tester",
|
|
2333
|
+
onClick: /* @__PURE__ */ __name(() => {
|
|
2334
|
+
if (!testerDraft.url) testerDraft.url = selected?.url ?? currentRoute ?? "";
|
|
2335
|
+
testerOpen.value = true;
|
|
2336
|
+
testerRevision && testerRevision.value++;
|
|
2337
|
+
}, "onClick")
|
|
2338
|
+
}), null);
|
|
2339
|
+
insertBefore(root, controls, null);
|
|
2340
|
+
const panes = createElement("div");
|
|
2341
|
+
setAttribute(panes, "class", "vobs-devtools-network-panes");
|
|
2342
|
+
const listPane = createElement("section");
|
|
2343
|
+
setAttribute(listPane, "class", "vobs-devtools-network-list-pane");
|
|
2344
|
+
setAttribute(listPane, "aria-label", "Network requests");
|
|
2345
|
+
const requestList = createElement("div");
|
|
2346
|
+
setAttribute(requestList, "class", "vobs-devtools-network-request-list");
|
|
2347
|
+
setAttribute(requestList, "role", "list");
|
|
2348
|
+
for (const entry of entries) {
|
|
2349
|
+
const row = createElement("button");
|
|
2350
|
+
const isSelected = selectedKey === entry.key;
|
|
2351
|
+
setAttribute(row, "class", `vobs-devtools-network-request${isSelected ? " is-selected" : ""}`);
|
|
2352
|
+
setAttribute(row, "type", "button");
|
|
2353
|
+
setAttribute(row, "role", "listitem");
|
|
2354
|
+
setAttribute(row, "aria-pressed", isSelected ? "true" : "false");
|
|
2355
|
+
row.addEventListener("click", () => {
|
|
2356
|
+
networkSelection && (networkSelection.value = entry.key);
|
|
2357
|
+
if (entry.request) onFocus("network", { type: "request", id: entry.request.id });
|
|
2358
|
+
if (detailTab) detailTab.value = "overview";
|
|
2359
|
+
});
|
|
2360
|
+
const pathLine = createElement("span");
|
|
2361
|
+
setAttribute(pathLine, "class", "vobs-devtools-network-request__path-line");
|
|
2362
|
+
appendText(pathLine, entry.url, "vobs-devtools-network-request__url");
|
|
2363
|
+
if (entry.request?.test) insertBefore(pathLine, createComponent(Tag, { tone: "warning", children: /* @__PURE__ */ __name(() => "TEST", "children") }), null);
|
|
2364
|
+
insertBefore(pathLine, createComponent(Tag, { tone: entry.status === "success" ? "success" : entry.status === "error" || entry.status === "cancelled" ? "danger" : "warning", children: /* @__PURE__ */ __name(() => entry.request?.responseStatus ? `${entry.status} ${entry.request.responseStatus}` : entry.status, "children") }), null);
|
|
2365
|
+
insertBefore(row, pathLine, null);
|
|
2366
|
+
const meta = createElement("span");
|
|
2367
|
+
setAttribute(meta, "class", "vobs-devtools-network-request__meta");
|
|
2368
|
+
appendText(meta, entry.duration === void 0 ? "Running" : `${entry.duration.toFixed(0)} ms`);
|
|
2369
|
+
appendText(meta, `ID ${entry.request?.id ?? entry.routerRequest?.id}`, "vobs-devtools-code");
|
|
2370
|
+
insertBefore(row, meta, null);
|
|
2371
|
+
insertBefore(requestList, row, null);
|
|
2372
|
+
}
|
|
2373
|
+
insertBefore(listPane, requestList, null);
|
|
2374
|
+
if (entries.length === 0) appendMuted(listPane, query || activeSource !== "all" || activeStatus !== "all" ? "No requests match the current filters." : "No requests recorded.");
|
|
2375
|
+
insertBefore(panes, listPane, null);
|
|
2376
|
+
const detailPane = createElement("section");
|
|
2377
|
+
setAttribute(detailPane, "class", "vobs-devtools-network-detail-pane");
|
|
2378
|
+
setAttribute(detailPane, "aria-label", "Selected network request");
|
|
2379
|
+
if (selected) insertBefore(detailPane, renderNetworkDetail(selected, detailTab?.value ?? "overview", (tab) => {
|
|
2380
|
+
if (detailTab) detailTab.value = tab;
|
|
2381
|
+
}), null);
|
|
2382
|
+
else appendMuted(detailPane, "Select a request to inspect its details.");
|
|
2383
|
+
insertBefore(panes, detailPane, null);
|
|
2384
|
+
insertBefore(root, panes, null);
|
|
2385
|
+
if (testerOpen?.value && testerDraft) insertBefore(root, renderRequestTester(testerDraft, (run) => {
|
|
2386
|
+
if (testerRun) testerRun.value = run;
|
|
2387
|
+
testerRevision && testerRevision.value++;
|
|
2388
|
+
}, testerRun?.value ?? { status: "idle" }, testerTab?.value ?? "params", selected, http, () => {
|
|
2389
|
+
testerOpen.value = false;
|
|
2390
|
+
}, (tab) => {
|
|
2391
|
+
if (testerTab) testerTab.value = tab;
|
|
2392
|
+
testerRevision && testerRevision.value++;
|
|
2393
|
+
}), null);
|
|
2394
|
+
return root;
|
|
2395
|
+
}
|
|
2396
|
+
__name(renderUnifiedNetworkRequests, "renderUnifiedNetworkRequests");
|
|
2397
|
+
function createNetworkFilterSelect(label, value, options, onChange) {
|
|
2398
|
+
const select = createElement("select");
|
|
2399
|
+
setAttribute(select, "class", "vobs-devtools-network-toolbar__select");
|
|
2400
|
+
setAttribute(select, "aria-label", label);
|
|
2401
|
+
setProperty(select, "value", value);
|
|
2402
|
+
for (const [optionValue, optionLabel] of options) {
|
|
2403
|
+
const option = createElement("option");
|
|
2404
|
+
setAttribute(option, "value", optionValue);
|
|
2405
|
+
insertBefore(option, createText(optionLabel), null);
|
|
2406
|
+
insertBefore(select, option, null);
|
|
2407
|
+
}
|
|
2408
|
+
setProperty(select, "value", value);
|
|
2409
|
+
select.addEventListener("change", (event) => onChange(event.target.value));
|
|
2410
|
+
return select;
|
|
2411
|
+
}
|
|
2412
|
+
__name(createNetworkFilterSelect, "createNetworkFilterSelect");
|
|
2413
|
+
function renderRequestTester(draft, onRunChange, run, activeTab, selected, http, onClose, onTabChange) {
|
|
2414
|
+
const drawer = createElement("aside");
|
|
2415
|
+
setAttribute(drawer, "class", "vobs-devtools-request-tester");
|
|
2416
|
+
setAttribute(drawer, "aria-label", "Request Tester");
|
|
2417
|
+
const heading = createElement("div");
|
|
2418
|
+
setAttribute(heading, "class", "vobs-devtools-request-tester__heading");
|
|
2419
|
+
appendText(heading, "Request Tester", "vobs-devtools-request-tester__title");
|
|
2420
|
+
const headingActions = createElement("div");
|
|
2421
|
+
setAttribute(headingActions, "class", "vobs-devtools-request-tester__heading-actions");
|
|
2422
|
+
insertBefore(headingActions, createComponent(Button, {
|
|
2423
|
+
variant: "ghost",
|
|
2424
|
+
disabled: !selected,
|
|
2425
|
+
children: /* @__PURE__ */ __name(() => "Use selected request", "children"),
|
|
2426
|
+
onClick: /* @__PURE__ */ __name(() => {
|
|
2427
|
+
if (!selected) return;
|
|
2428
|
+
applyNetworkEntryToTesterDraft(selected, draft);
|
|
2429
|
+
onRunChange({ status: "idle" });
|
|
2430
|
+
}, "onClick")
|
|
2431
|
+
}), null);
|
|
2432
|
+
insertBefore(headingActions, createComponent(Button, {
|
|
2433
|
+
variant: "ghost",
|
|
2434
|
+
iconOnly: true,
|
|
2435
|
+
icon: createComponent(Icon, { name: "x" }),
|
|
2436
|
+
"aria-label": "Close Request Tester",
|
|
2437
|
+
title: "Close Request Tester",
|
|
2438
|
+
onClick: onClose
|
|
2439
|
+
}), null);
|
|
2440
|
+
insertBefore(heading, headingActions, null);
|
|
2441
|
+
insertBefore(drawer, heading, null);
|
|
2442
|
+
const requestLine = createElement("div");
|
|
2443
|
+
setAttribute(requestLine, "class", "vobs-devtools-request-tester__request-line");
|
|
2444
|
+
insertBefore(requestLine, createTesterInput("url", draft.url, (value) => {
|
|
2445
|
+
draft.url = value;
|
|
2446
|
+
}), null);
|
|
2447
|
+
insertBefore(requestLine, createTesterMethodSelect(draft.method, (value) => {
|
|
2448
|
+
draft.method = value;
|
|
2449
|
+
onRunChange({ status: run.status, message: run.message });
|
|
2450
|
+
}), null);
|
|
2451
|
+
insertBefore(requestLine, createComponent(Button, {
|
|
2452
|
+
variant: "brand",
|
|
2453
|
+
iconOnly: true,
|
|
2454
|
+
icon: createComponent(Icon, { name: "play" }),
|
|
2455
|
+
loading: run.status === "running",
|
|
2456
|
+
disabled: run.status === "running",
|
|
2457
|
+
"aria-label": run.status === "running" ? "Running request" : "Start request",
|
|
2458
|
+
title: run.status === "running" ? "Running request" : "Start request",
|
|
2459
|
+
onClick: /* @__PURE__ */ __name(() => {
|
|
2460
|
+
void executeRequestTester(http, draft, onRunChange);
|
|
2461
|
+
}, "onClick")
|
|
2462
|
+
}), null);
|
|
2463
|
+
insertBefore(drawer, requestLine, null);
|
|
2464
|
+
const tabs = createElement("div");
|
|
2465
|
+
setAttribute(tabs, "class", "vobs-devtools-request-tester__tabs");
|
|
2466
|
+
const tabLabels = [["params", "Params"], ["headers", "Headers"], ["body", "Body"]];
|
|
2467
|
+
for (const [tab, label] of tabLabels) {
|
|
2468
|
+
const button = createElement("button");
|
|
2469
|
+
setAttribute(button, "class", `vobs-devtools-request-tester__tab${activeTab === tab ? " is-active" : ""}`);
|
|
2470
|
+
setAttribute(button, "type", "button");
|
|
2471
|
+
setAttribute(button, "aria-selected", activeTab === tab ? "true" : "false");
|
|
2472
|
+
appendText(button, label);
|
|
2473
|
+
button.addEventListener("click", () => onTabChange(tab));
|
|
2474
|
+
insertBefore(tabs, button, null);
|
|
2475
|
+
}
|
|
2476
|
+
insertBefore(drawer, tabs, null);
|
|
2477
|
+
if (activeTab === "params") insertBefore(drawer, renderTesterParamGroup("Params", draft.params, "parameter", onRunChange), null);
|
|
2478
|
+
if (activeTab === "headers") insertBefore(drawer, renderTesterParamGroup("Headers", draft.headers, "header", onRunChange), null);
|
|
2479
|
+
if (activeTab === "body") {
|
|
2480
|
+
const bodyLabel = createElement("label");
|
|
2481
|
+
setAttribute(bodyLabel, "class", "vobs-devtools-request-tester__field");
|
|
2482
|
+
appendText(bodyLabel, "Body");
|
|
2483
|
+
const body = createElement("textarea");
|
|
2484
|
+
setAttribute(body, "class", "vobs-devtools-request-tester__textarea");
|
|
2485
|
+
setAttribute(body, "rows", "8");
|
|
2486
|
+
setAttribute(body, "placeholder", '{ "key": "value" }');
|
|
2487
|
+
setProperty(body, "value", draft.body);
|
|
2488
|
+
body.addEventListener("change", () => {
|
|
2489
|
+
draft.body = body.value;
|
|
2490
|
+
});
|
|
2491
|
+
insertBefore(bodyLabel, body, null);
|
|
2492
|
+
insertBefore(drawer, bodyLabel, null);
|
|
2493
|
+
}
|
|
2494
|
+
const footer = createElement("div");
|
|
2495
|
+
setAttribute(footer, "class", "vobs-devtools-request-tester__footer");
|
|
2496
|
+
if (run.message) appendText(footer, run.message, `vobs-devtools-request-tester__status${run.status === "error" ? " is-error" : run.status === "success" ? " is-success" : ""}`);
|
|
2497
|
+
insertBefore(drawer, footer, null);
|
|
2498
|
+
return drawer;
|
|
2499
|
+
}
|
|
2500
|
+
__name(renderRequestTester, "renderRequestTester");
|
|
2501
|
+
function applyNetworkEntryToTesterDraft(entry, draft) {
|
|
2502
|
+
const request = entry.request;
|
|
2503
|
+
const rawUrl = request?.url ?? entry.url;
|
|
2504
|
+
let url = rawUrl;
|
|
2505
|
+
let params = [];
|
|
2506
|
+
try {
|
|
2507
|
+
const parsed = new URL(rawUrl, typeof window !== "undefined" ? window.location.href : "http://localhost/");
|
|
2508
|
+
url = `${parsed.origin === "http://localhost" && rawUrl.startsWith("/") ? "" : parsed.origin}${parsed.pathname}${parsed.hash}`;
|
|
2509
|
+
params = [...parsed.searchParams.entries()].map(([key, value]) => ({ key, value }));
|
|
2510
|
+
} catch {
|
|
2511
|
+
}
|
|
2512
|
+
draft.url = url;
|
|
2513
|
+
draft.method = isHTTPMethod(request?.method ?? entry.method) ? request?.method ?? entry.method : "GET";
|
|
2514
|
+
draft.params = params.length > 0 ? params : [{ key: "", value: "" }];
|
|
2515
|
+
draft.headers = request ? Object.entries(request.headers).map(([key, value]) => ({ key, value })) : [{ key: "", value: "" }];
|
|
2516
|
+
const body = request?.requestBody;
|
|
2517
|
+
draft.body = body === void 0 || body === null || body === "" ? "" : typeof body === "string" ? body : JSON.stringify(body, null, 2);
|
|
2518
|
+
}
|
|
2519
|
+
__name(applyNetworkEntryToTesterDraft, "applyNetworkEntryToTesterDraft");
|
|
2520
|
+
function isHTTPMethod(value) {
|
|
2521
|
+
return ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"].includes(value);
|
|
2522
|
+
}
|
|
2523
|
+
__name(isHTTPMethod, "isHTTPMethod");
|
|
2524
|
+
function createTesterInput(name, value, onChange) {
|
|
2525
|
+
const input = createElement("input");
|
|
2526
|
+
setAttribute(input, "class", "vobs-devtools-request-tester__input");
|
|
2527
|
+
setAttribute(input, "name", name);
|
|
2528
|
+
setAttribute(input, "type", "text");
|
|
2529
|
+
setProperty(input, "value", value);
|
|
2530
|
+
input.addEventListener("change", () => onChange(input.value));
|
|
2531
|
+
return input;
|
|
2532
|
+
}
|
|
2533
|
+
__name(createTesterInput, "createTesterInput");
|
|
2534
|
+
function createTesterMethodSelect(value, onChange) {
|
|
2535
|
+
const select = createElement("select");
|
|
2536
|
+
setAttribute(select, "class", "vobs-devtools-request-tester__select");
|
|
2537
|
+
for (const method of ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]) {
|
|
2538
|
+
const option = createElement("option");
|
|
2539
|
+
setAttribute(option, "value", method);
|
|
2540
|
+
if (method === value) setAttribute(option, "selected", "");
|
|
2541
|
+
insertBefore(option, createText(method), null);
|
|
2542
|
+
insertBefore(select, option, null);
|
|
2543
|
+
}
|
|
2544
|
+
select.addEventListener("change", () => onChange(select.value));
|
|
2545
|
+
return select;
|
|
2546
|
+
}
|
|
2547
|
+
__name(createTesterMethodSelect, "createTesterMethodSelect");
|
|
2548
|
+
function renderTesterParamGroup(label, params, singular, onChange) {
|
|
2549
|
+
const group = createElement("section");
|
|
2550
|
+
setAttribute(group, "class", "vobs-devtools-request-tester__group");
|
|
2551
|
+
const title = createElement("div");
|
|
2552
|
+
setAttribute(title, "class", "vobs-devtools-request-tester__group-title");
|
|
2553
|
+
appendText(title, label);
|
|
2554
|
+
const add = createElement("button");
|
|
2555
|
+
setAttribute(add, "class", "vobs-devtools-request-tester__add");
|
|
2556
|
+
setAttribute(add, "type", "button");
|
|
2557
|
+
appendText(add, "+");
|
|
2558
|
+
setAttribute(add, "aria-label", `Add ${label}`);
|
|
2559
|
+
setAttribute(add, "title", `Add ${label}`);
|
|
2560
|
+
add.addEventListener("click", () => {
|
|
2561
|
+
params.push({ key: "", value: "" });
|
|
2562
|
+
onChange({ status: "idle" });
|
|
2563
|
+
});
|
|
2564
|
+
insertBefore(title, add, null);
|
|
2565
|
+
insertBefore(group, title, null);
|
|
2566
|
+
for (let index = 0; index < params.length; index++) {
|
|
2567
|
+
const param = params[index];
|
|
2568
|
+
const row = createElement("div");
|
|
2569
|
+
setAttribute(row, "class", "vobs-devtools-request-tester__param");
|
|
2570
|
+
insertBefore(row, createTesterInput(`${singular}-key-${index}`, param.key, (value) => {
|
|
2571
|
+
param.key = value;
|
|
2572
|
+
}), null);
|
|
2573
|
+
insertBefore(row, createTesterInput(`${singular}-value-${index}`, param.value, (value) => {
|
|
2574
|
+
param.value = value;
|
|
2575
|
+
}), null);
|
|
2576
|
+
const remove = createElement("button");
|
|
2577
|
+
setAttribute(remove, "class", "vobs-devtools-request-tester__remove");
|
|
2578
|
+
setAttribute(remove, "type", "button");
|
|
2579
|
+
setAttribute(remove, "aria-label", `Remove ${label} row ${index + 1}`);
|
|
2580
|
+
setAttribute(remove, "title", `Remove ${label} row ${index + 1}`);
|
|
2581
|
+
insertBefore(remove, createComponent(Icon, { name: "trash" }), null);
|
|
2582
|
+
remove.addEventListener("click", () => {
|
|
2583
|
+
params.splice(index, 1);
|
|
2584
|
+
if (params.length === 0) params.push({ key: "", value: "" });
|
|
2585
|
+
onChange({ status: "idle" });
|
|
2586
|
+
});
|
|
2587
|
+
insertBefore(row, remove, null);
|
|
2588
|
+
insertBefore(group, row, null);
|
|
2589
|
+
}
|
|
2590
|
+
return group;
|
|
2591
|
+
}
|
|
2592
|
+
__name(renderTesterParamGroup, "renderTesterParamGroup");
|
|
2593
|
+
async function executeRequestTester(http, draft, onRunChange) {
|
|
2594
|
+
if (!http) {
|
|
2595
|
+
onRunChange({ status: "error", message: "HTTP client is unavailable." });
|
|
2596
|
+
return;
|
|
2597
|
+
}
|
|
2598
|
+
const url = draft.url.trim();
|
|
2599
|
+
if (!url) {
|
|
2600
|
+
onRunChange({ status: "error", message: "Enter a request URL." });
|
|
2601
|
+
return;
|
|
2602
|
+
}
|
|
2603
|
+
const params = {};
|
|
2604
|
+
for (const param of draft.params) if (param.key.trim()) params[param.key.trim()] = param.value;
|
|
2605
|
+
const headers = {};
|
|
2606
|
+
for (const header of draft.headers) if (header.key.trim()) headers[header.key.trim()] = header.value;
|
|
2607
|
+
let body;
|
|
2608
|
+
if (!["GET", "HEAD", "DELETE"].includes(draft.method) && draft.body.trim()) {
|
|
2609
|
+
try {
|
|
2610
|
+
body = JSON.parse(draft.body);
|
|
2611
|
+
} catch {
|
|
2612
|
+
onRunChange({ status: "error", message: "Body must be valid JSON." });
|
|
2613
|
+
return;
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
onRunChange({ status: "running", message: void 0 });
|
|
2617
|
+
try {
|
|
2618
|
+
await http.request({
|
|
2619
|
+
url,
|
|
2620
|
+
method: draft.method,
|
|
2621
|
+
params: Object.keys(params).length > 0 ? params : void 0,
|
|
2622
|
+
headers: Object.keys(headers).length > 0 ? headers : void 0,
|
|
2623
|
+
body,
|
|
2624
|
+
debugContext: { route: url, test: true }
|
|
2625
|
+
});
|
|
2626
|
+
onRunChange({ status: "success", message: "Request completed." });
|
|
2627
|
+
} catch (error) {
|
|
2628
|
+
onRunChange({ status: "error", message: error instanceof Error ? error.message : String(error) });
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
__name(executeRequestTester, "executeRequestTester");
|
|
2632
|
+
function renderNetworkDetail(entry, activeTab, onTabChange) {
|
|
2633
|
+
const root = createElement("section");
|
|
2634
|
+
setAttribute(root, "class", "vobs-devtools-network-detail");
|
|
2635
|
+
const request = entry.request;
|
|
2636
|
+
const routerRequest = entry.routerRequest;
|
|
2637
|
+
const heading = createElement("div");
|
|
2638
|
+
setAttribute(heading, "class", "vobs-devtools-network-detail__heading");
|
|
2639
|
+
appendText(heading, `${entry.method} ${entry.url}`, "vobs-devtools-network-detail__title");
|
|
2640
|
+
if (request?.test) insertBefore(heading, createComponent(Tag, { tone: "warning", children: /* @__PURE__ */ __name(() => "TEST", "children") }), null);
|
|
2641
|
+
insertBefore(heading, createComponent(Tag, { tone: entry.status === "success" ? "success" : entry.status === "error" || entry.status === "cancelled" ? "danger" : "warning", children: /* @__PURE__ */ __name(() => request?.responseStatus ? `${entry.status} ${request.responseStatus}` : entry.status, "children") }), null);
|
|
2642
|
+
if (entry.duration !== void 0) appendText(heading, `${entry.duration.toFixed(0)} ms`, "vobs-devtools-network-detail__duration");
|
|
2643
|
+
insertBefore(root, heading, null);
|
|
2644
|
+
const tabs = createElement("div");
|
|
2645
|
+
setAttribute(tabs, "class", "vobs-devtools-network-detail__tabs");
|
|
2646
|
+
const tabLabels = [["overview", "Overview"], ["headers", "Headers"], ["payload", "Payload"], ["response", "Response"], ["timing", "Timing"], ["context", "Context"]];
|
|
2647
|
+
for (const [tab, label] of tabLabels) {
|
|
2648
|
+
const button = createElement("button");
|
|
2649
|
+
setAttribute(button, "type", "button");
|
|
2650
|
+
setAttribute(button, "class", `vobs-devtools-network-detail__tab${activeTab === tab ? " is-active" : ""}`);
|
|
2651
|
+
setAttribute(button, "aria-selected", activeTab === tab ? "true" : "false");
|
|
2652
|
+
appendText(button, label);
|
|
2653
|
+
button.addEventListener("click", () => onTabChange(tab));
|
|
2654
|
+
insertBefore(tabs, button, null);
|
|
2655
|
+
}
|
|
2656
|
+
insertBefore(root, tabs, null);
|
|
2657
|
+
const content = createElement("div");
|
|
2658
|
+
setAttribute(content, "class", "vobs-devtools-network-detail__content");
|
|
2659
|
+
if (activeTab === "overview") {
|
|
2660
|
+
appendNetworkField(content, "Source", entry.source.toUpperCase());
|
|
2661
|
+
appendNetworkField(content, "Method / Type", entry.method);
|
|
2662
|
+
appendNetworkField(content, "Request key", entry.url, "code");
|
|
2663
|
+
appendNetworkField(content, "Status", entry.status);
|
|
2664
|
+
if (request?.error || routerRequest?.error) appendText(content, request ? `${request.error?.name}: ${request.error?.message}` : routerRequest.error, "vobs-devtools-error");
|
|
2665
|
+
} else if (activeTab === "headers") {
|
|
2666
|
+
if (request && Object.keys(request.headers).length > 0) insertBefore(content, renderValueTree("Headers", request.headers, false), null);
|
|
2667
|
+
else appendMuted(content, "No captured headers for this request.");
|
|
2668
|
+
} else if (activeTab === "payload") {
|
|
2669
|
+
const payload = request?.requestBody;
|
|
2670
|
+
if (payload !== void 0) insertBefore(content, renderValueTree("Request body", payload, false), null);
|
|
2671
|
+
else appendMuted(content, "No request payload captured.");
|
|
2672
|
+
} else if (activeTab === "response") {
|
|
2673
|
+
const response = request?.responseBody ?? routerRequest?.result;
|
|
2674
|
+
if (response !== void 0) insertBefore(content, renderValueTree("Response", response, false), null);
|
|
2675
|
+
else appendMuted(content, routerRequest?.error ?? "No response body captured.");
|
|
2676
|
+
} else if (activeTab === "timing") {
|
|
2677
|
+
if (entry.startedAt !== void 0) appendNetworkField(content, "Started at", formatNetworkTimestamp(entry.startedAt));
|
|
2678
|
+
if (entry.endedAt !== void 0) appendNetworkField(content, "Ended at", formatNetworkTimestamp(entry.endedAt));
|
|
2679
|
+
appendNetworkField(content, "Duration", entry.duration === void 0 ? "Running" : `${entry.duration.toFixed(2)} ms`);
|
|
2680
|
+
if (request) appendNetworkField(content, "Attempts", `${request.attempt + 1} (${request.retries} retries)`);
|
|
2681
|
+
} else {
|
|
2682
|
+
appendNetworkField(content, "Environment", request?.environment ?? routerRequest?.environment ?? "client");
|
|
2683
|
+
if (request?.route ?? routerRequest?.route) appendNetworkField(content, "Route", request?.route ?? routerRequest?.route ?? "", "code");
|
|
2684
|
+
if (request?.navigationId ?? routerRequest?.navigationId) appendNetworkField(content, "Navigation ID", String(request?.navigationId ?? routerRequest?.navigationId), "code");
|
|
2685
|
+
if (request?.dataRequestId !== void 0) appendNetworkField(content, "Data request ID", String(request.dataRequestId), "code");
|
|
2686
|
+
if (routerRequest?.trigger) appendNetworkField(content, "Trigger", routerRequest.trigger);
|
|
2687
|
+
appendNetworkField(content, "Request ID", String(request?.id ?? routerRequest?.id), "code");
|
|
2688
|
+
}
|
|
2689
|
+
insertBefore(root, content, null);
|
|
2690
|
+
return root;
|
|
2691
|
+
}
|
|
2692
|
+
__name(renderNetworkDetail, "renderNetworkDetail");
|
|
2693
|
+
function appendNetworkField(parent, label, value, valueKind) {
|
|
2694
|
+
const field = createElement("div");
|
|
2695
|
+
setAttribute(field, "class", "vobs-devtools-network-detail__field");
|
|
2696
|
+
appendText(field, label, "vobs-devtools-network-detail__label");
|
|
2697
|
+
appendText(field, value, `vobs-devtools-network-detail__value${valueKind ? ` vobs-devtools-${valueKind}` : ""}`);
|
|
2698
|
+
insertBefore(parent, field, null);
|
|
2699
|
+
}
|
|
2700
|
+
__name(appendNetworkField, "appendNetworkField");
|
|
2701
|
+
function formatNetworkTimestamp(value) {
|
|
2702
|
+
const epoch = value > 1e11 ? value : typeof performance !== "undefined" ? performance.timeOrigin + value : Date.now();
|
|
2703
|
+
return new Date(epoch).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" });
|
|
2704
|
+
}
|
|
2705
|
+
__name(formatNetworkTimestamp, "formatNetworkTimestamp");
|
|
2706
|
+
function matchesQuery(query, ...values) {
|
|
2707
|
+
const needle = query.trim().toLowerCase();
|
|
2708
|
+
if (!needle) return true;
|
|
2709
|
+
return values.some((value) => String(value ?? "").toLowerCase().includes(needle));
|
|
2710
|
+
}
|
|
2711
|
+
__name(matchesQuery, "matchesQuery");
|
|
2712
|
+
function filterErrors(errors, query) {
|
|
2713
|
+
return errors.filter((error) => matchesQuery(query, error.phase, error.phases, error.origin, error.code, error.name, error.message, error.component, error.route, error.id, error.effectId, error.requestId));
|
|
2714
|
+
}
|
|
2715
|
+
__name(filterErrors, "filterErrors");
|
|
2716
|
+
function filterComponentTree(nodes, query) {
|
|
2717
|
+
if (!query.trim()) return nodes;
|
|
2718
|
+
return nodes.flatMap((node) => {
|
|
2719
|
+
const children = filterComponentTree(node.children, query);
|
|
2720
|
+
if (!matchesQuery(query, node.name, node.id) && children.length === 0) return [];
|
|
2721
|
+
return [{ ...node, children }];
|
|
2722
|
+
});
|
|
2723
|
+
}
|
|
2724
|
+
__name(filterComponentTree, "filterComponentTree");
|
|
2725
|
+
function renderErrors(errors, selection, onFocus) {
|
|
2726
|
+
const root = createElement("div");
|
|
2727
|
+
setAttribute(root, "class", "vobs-devtools-error-list");
|
|
2728
|
+
for (const error of [...errors].reverse()) {
|
|
2729
|
+
const row = createElement("details");
|
|
2730
|
+
const selected = selection?.type === "error" && selection.id === error.id;
|
|
2731
|
+
setAttribute(row, "class", `vobs-devtools-list__row vobs-devtools-error-item${selected ? " is-selected" : ""}`);
|
|
2732
|
+
if (selected) setProperty(row, "open", true);
|
|
2733
|
+
row.addEventListener("click", (event) => {
|
|
2734
|
+
event.stopPropagation();
|
|
2735
|
+
onFocus("errors", { type: "error", id: error.id });
|
|
2736
|
+
});
|
|
2737
|
+
const summary = createElement("summary");
|
|
2738
|
+
appendText(summary, formatErrorSummary(error), "vobs-devtools-list__name");
|
|
2739
|
+
appendText(summary, error.message, "vobs-devtools-error-item__message");
|
|
2740
|
+
insertBefore(summary, createComponent(Tag, { tone: error.origin === "framework" ? "danger" : error.origin === "usage" ? "warning" : "neutral-strong", children: /* @__PURE__ */ __name(() => error.origin, "children") }), null);
|
|
2741
|
+
insertBefore(summary, createComponent(Tag, { tone: "danger", children: /* @__PURE__ */ __name(() => `${error.count}\xD7`, "children") }), null);
|
|
2742
|
+
insertBefore(row, summary, null);
|
|
2743
|
+
const details = createElement("div");
|
|
2744
|
+
setAttribute(details, "class", "vobs-devtools-error-item__details");
|
|
2745
|
+
appendErrorField(details, "Phase", error.phases.length > 1 ? error.phases.join(" / ") : error.phase);
|
|
2746
|
+
appendErrorField(details, "Occurred", `first ${new Date(error.firstOccurredAt).toLocaleString()} \xB7 last ${new Date(error.lastOccurredAt).toLocaleString()}`, "muted");
|
|
2747
|
+
if (error.code) appendErrorField(details, "Code", error.code, "code");
|
|
2748
|
+
if (error.component) appendErrorField(details, "Component", displayErrorComponent(error.component));
|
|
2749
|
+
if (error.ownerId) appendErrorField(details, "Owner", error.ownerId, "code");
|
|
2750
|
+
appendErrorField(details, "Status", `${error.handled ? "handled" : "propagated"} \xB7 ${error.recovery}`, "muted");
|
|
2751
|
+
if (error.hint) appendErrorField(details, "Hint", error.hint, "muted", true);
|
|
2752
|
+
if (error.cause) appendErrorField(details, "Cause", error.cause, "muted", true);
|
|
2753
|
+
if (error.fix) appendErrorField(details, "Fix", error.fix, "muted", true);
|
|
2754
|
+
if (error.source) appendErrorField(details, "Source", formatDebugLocation(error.source), "code", true);
|
|
2755
|
+
if (error.updateId) appendErrorLinkField(details, "Update", error.updateId, "updates", { type: "update", id: error.updateId }, onFocus);
|
|
2756
|
+
if (error.effectId) appendErrorField(details, "Effect", error.effectId, "code");
|
|
2757
|
+
if (error.requestId !== void 0) appendErrorLinkField(details, "Request", String(error.requestId), "network", { type: "request", id: error.requestId }, onFocus);
|
|
2758
|
+
if (error.navigationId !== void 0) appendErrorField(details, "Navigation", String(error.navigationId), "code");
|
|
2759
|
+
if (error.route) appendErrorField(details, "Route", error.route, "code");
|
|
2760
|
+
if (error.hydration) {
|
|
2761
|
+
appendErrorField(details, "Expected", error.hydration.expected, "code", true);
|
|
2762
|
+
appendErrorField(details, "Actual", error.hydration.actual, "code", true);
|
|
2763
|
+
appendErrorField(details, "DOM path", error.hydration.path, "code");
|
|
2764
|
+
}
|
|
2765
|
+
if (error.stack) appendErrorStack(details, error.stack, error.name, error.message);
|
|
2766
|
+
insertBefore(row, details, null);
|
|
2767
|
+
insertBefore(root, row, null);
|
|
2768
|
+
}
|
|
2769
|
+
if (errors.length === 0) appendMuted(root, "No errors recorded.");
|
|
2770
|
+
return root;
|
|
2771
|
+
}
|
|
2772
|
+
__name(renderErrors, "renderErrors");
|
|
2773
|
+
function appendContextLink(parent, label, section, selection, onFocus) {
|
|
2774
|
+
const button = createElement("button");
|
|
2775
|
+
setAttribute(button, "class", "vobs-devtools-link");
|
|
2776
|
+
setAttribute(button, "type", "button");
|
|
2777
|
+
button.addEventListener("click", (event) => {
|
|
2778
|
+
event.stopPropagation();
|
|
2779
|
+
onFocus(section, selection);
|
|
2780
|
+
});
|
|
2781
|
+
insertBefore(button, createText(label), null);
|
|
2782
|
+
insertBefore(parent, button, null);
|
|
2783
|
+
}
|
|
2784
|
+
__name(appendContextLink, "appendContextLink");
|
|
2785
|
+
function appendErrorField(parent, label, value, valueKind, wide = false) {
|
|
2786
|
+
const field = createElement("div");
|
|
2787
|
+
setAttribute(field, "class", `vobs-devtools-error-item__field${wide ? " vobs-devtools-error-item__field--wide" : ""}`);
|
|
2788
|
+
appendText(field, label, "vobs-devtools-error-item__label");
|
|
2789
|
+
appendText(field, value, `vobs-devtools-error-item__value${valueKind ? ` vobs-devtools-${valueKind}` : ""}`);
|
|
2790
|
+
insertBefore(parent, field, null);
|
|
2791
|
+
}
|
|
2792
|
+
__name(appendErrorField, "appendErrorField");
|
|
2793
|
+
function appendErrorLinkField(parent, label, value, section, selection, onFocus) {
|
|
2794
|
+
const field = createElement("div");
|
|
2795
|
+
setAttribute(field, "class", "vobs-devtools-error-item__field");
|
|
2796
|
+
appendText(field, label, "vobs-devtools-error-item__label");
|
|
2797
|
+
const valueNode = createElement("span");
|
|
2798
|
+
setAttribute(valueNode, "class", "vobs-devtools-error-item__value");
|
|
2799
|
+
appendContextLink(valueNode, value, section, selection, onFocus);
|
|
2800
|
+
insertBefore(field, valueNode, null);
|
|
2801
|
+
insertBefore(parent, field, null);
|
|
2802
|
+
}
|
|
2803
|
+
__name(appendErrorLinkField, "appendErrorLinkField");
|
|
2804
|
+
function appendErrorStack(parent, value, name, message) {
|
|
2805
|
+
const stack = createElement("div");
|
|
2806
|
+
setAttribute(stack, "class", "vobs-devtools-error-item__stack");
|
|
2807
|
+
appendText(stack, "Stack trace", "vobs-devtools-error-item__label");
|
|
2808
|
+
const code = createElement("pre");
|
|
2809
|
+
setAttribute(code, "class", "vobs-devtools-error-item__stack-code vobs-devtools-code");
|
|
2810
|
+
insertBefore(code, createText(formatDebugStack(value, name, message)), null);
|
|
2811
|
+
insertBefore(stack, code, null);
|
|
2812
|
+
insertBefore(parent, stack, null);
|
|
2813
|
+
}
|
|
2814
|
+
__name(appendErrorStack, "appendErrorStack");
|
|
2815
|
+
function formatErrorSummary(error) {
|
|
2816
|
+
const phase = error.phases.length > 1 ? error.phases.join(" / ") : error.phase;
|
|
2817
|
+
return error.name === "Error" ? phase : `${phase} \xB7 ${error.name}`;
|
|
2818
|
+
}
|
|
2819
|
+
__name(formatErrorSummary, "formatErrorSummary");
|
|
2820
|
+
function lifecycleSelection(event) {
|
|
2821
|
+
if (event.type.startsWith("owner-")) return { type: "component", id: event.targetId };
|
|
2822
|
+
if (event.type.startsWith("signal-") || event.type.startsWith("memo-")) return { type: "signal", id: event.targetId };
|
|
2823
|
+
if (event.type.startsWith("effect-")) return { type: "effect", id: event.targetId };
|
|
2824
|
+
return null;
|
|
2825
|
+
}
|
|
2826
|
+
__name(lifecycleSelection, "lifecycleSelection");
|
|
2827
|
+
function displaySignalName(signal) {
|
|
2828
|
+
if (!signal.name.startsWith("signal-")) return stripDebugLocation(signal.name);
|
|
2829
|
+
const component = formatDebugLocation(signal.component);
|
|
2830
|
+
return component === "unknown" ? "runtime state" : `${debugComponentName(component)} state`;
|
|
2831
|
+
}
|
|
2832
|
+
__name(displaySignalName, "displaySignalName");
|
|
2833
|
+
function displayDebugName(name) {
|
|
2834
|
+
return name.startsWith("signal-") ? "runtime state" : stripDebugLocation(name);
|
|
2835
|
+
}
|
|
2836
|
+
__name(displayDebugName, "displayDebugName");
|
|
2837
|
+
function debugComponentName(value) {
|
|
2838
|
+
const separator = value.indexOf(" (");
|
|
2839
|
+
return separator > 0 ? value.slice(0, separator) : value;
|
|
2840
|
+
}
|
|
2841
|
+
__name(debugComponentName, "debugComponentName");
|
|
2842
|
+
function displayErrorComponent(value) {
|
|
2843
|
+
return debugComponentName(formatDebugLocation(value));
|
|
2844
|
+
}
|
|
2845
|
+
__name(displayErrorComponent, "displayErrorComponent");
|
|
2846
|
+
function appendText(parent, value, className) {
|
|
2847
|
+
const node = createElement("span");
|
|
2848
|
+
if (className) setAttribute(node, "class", className);
|
|
2849
|
+
insertBefore(node, createText(value), null);
|
|
2850
|
+
insertBefore(parent, node, null);
|
|
2851
|
+
}
|
|
2852
|
+
__name(appendText, "appendText");
|
|
2853
|
+
function formatDebugLocation(value) {
|
|
2854
|
+
const normalized = value.replaceAll("\\", "/");
|
|
2855
|
+
const lower = normalized.toLowerCase();
|
|
2856
|
+
const sourceIndex = lower.startsWith("src/") ? 0 : lower.indexOf("/src/") + 1;
|
|
2857
|
+
if (sourceIndex <= 0 && !lower.startsWith("src/")) return normalized;
|
|
2858
|
+
const sourcePath = normalized.slice(sourceIndex);
|
|
2859
|
+
const openParen = normalized.lastIndexOf("(", sourceIndex);
|
|
2860
|
+
return openParen >= 0 ? `${normalized.slice(0, openParen + 1)}${sourcePath}` : sourcePath;
|
|
2861
|
+
}
|
|
2862
|
+
__name(formatDebugLocation, "formatDebugLocation");
|
|
2863
|
+
function formatDebugStack(value, name, message) {
|
|
2864
|
+
const lines = value.split(/\r?\n/).map(formatDebugStackLine);
|
|
2865
|
+
const first = lines[0]?.trim();
|
|
2866
|
+
const header = `${name}: ${message}`;
|
|
2867
|
+
if (lines.length > 1 && (first === header || first?.startsWith(`${header} `))) return lines.slice(1).join("\n");
|
|
2868
|
+
return lines.join("\n");
|
|
2869
|
+
}
|
|
2870
|
+
__name(formatDebugStack, "formatDebugStack");
|
|
2871
|
+
function formatDebugStackLine(value) {
|
|
2872
|
+
const normalized = value.replaceAll("\\", "/");
|
|
2873
|
+
const lower = normalized.toLowerCase();
|
|
2874
|
+
const sourceIndex = lower.startsWith("src/") ? 0 : lower.indexOf("/src/") + 1;
|
|
2875
|
+
if (sourceIndex < 0) return normalized;
|
|
2876
|
+
if (sourceIndex === 0) return normalized;
|
|
2877
|
+
const prefixBeforeLocation = normalized.slice(0, sourceIndex);
|
|
2878
|
+
const openParen = prefixBeforeLocation.lastIndexOf("(");
|
|
2879
|
+
const openBracket = prefixBeforeLocation.lastIndexOf("[");
|
|
2880
|
+
const opening = Math.max(openParen, openBracket);
|
|
2881
|
+
if (opening >= 0) return `${normalized.slice(0, opening + 1)}${normalized.slice(sourceIndex)}`;
|
|
2882
|
+
const at = prefixBeforeLocation.lastIndexOf("at ");
|
|
2883
|
+
return at >= 0 ? `${normalized.slice(0, at + 3)}${normalized.slice(sourceIndex)}` : normalized.slice(sourceIndex);
|
|
2884
|
+
}
|
|
2885
|
+
__name(formatDebugStackLine, "formatDebugStackLine");
|
|
2886
|
+
function formatDebugSource(value) {
|
|
2887
|
+
const location = formatDebugLocation(value);
|
|
2888
|
+
const openParen = location.indexOf("(");
|
|
2889
|
+
if (openParen < 0) return location;
|
|
2890
|
+
const closeParen = location.indexOf(")", openParen);
|
|
2891
|
+
return closeParen < 0 ? location : location.slice(openParen + 1, closeParen);
|
|
2892
|
+
}
|
|
2893
|
+
__name(formatDebugSource, "formatDebugSource");
|
|
2894
|
+
function stripDebugLocation(value) {
|
|
2895
|
+
const normalized = value.replaceAll("\\", "/");
|
|
2896
|
+
const lower = normalized.toLowerCase();
|
|
2897
|
+
const sourceIndex = lower.startsWith("src/") ? 0 : lower.indexOf("/src/") + 1;
|
|
2898
|
+
if (sourceIndex <= 0 && !lower.startsWith("src/")) return normalized;
|
|
2899
|
+
const openParen = normalized.lastIndexOf("(", sourceIndex);
|
|
2900
|
+
if (openParen < 0) return normalized;
|
|
2901
|
+
const closeParen = normalized.indexOf(")", sourceIndex);
|
|
2902
|
+
if (closeParen < 0) return normalized;
|
|
2903
|
+
return `${normalized.slice(0, openParen)}${normalized.slice(closeParen + 1)}`.trim();
|
|
2904
|
+
}
|
|
2905
|
+
__name(stripDebugLocation, "stripDebugLocation");
|
|
2906
|
+
function renderComponentSummary(node, snapshot, selection, onFocus) {
|
|
2907
|
+
const row = createElement("details");
|
|
2908
|
+
const selected = selection?.type === "component" && selection.id === node.id;
|
|
2909
|
+
setAttribute(row, "class", `vobs-devtools-list__row vobs-devtools-component-row${selected ? " is-selected" : ""}`);
|
|
2910
|
+
if (selected) setProperty(row, "open", true);
|
|
2911
|
+
row.addEventListener("click", (event) => {
|
|
2912
|
+
event.stopPropagation();
|
|
2913
|
+
onFocus("components", { type: "component", id: node.id });
|
|
2914
|
+
});
|
|
2915
|
+
const summary = createElement("summary");
|
|
2916
|
+
appendText(summary, formatDebugLocation(node.name), "vobs-devtools-list__name");
|
|
2917
|
+
insertBefore(summary, createComponent(Tag, { tone: node.mounted ? "success" : "neutral-strong", children: /* @__PURE__ */ __name(() => `${node.signals.length} signals`, "children") }), null);
|
|
2918
|
+
insertBefore(summary, createComponent(Tag, { tone: "neutral-strong", children: /* @__PURE__ */ __name(() => `${node.effects.length} effects`, "children") }), null);
|
|
2919
|
+
appendText(summary, `${node.recentUpdates.length} updates \xB7 ${node.domUpdates} DOM`, "vobs-devtools-muted");
|
|
2920
|
+
insertBefore(row, summary, null);
|
|
2921
|
+
appendText(row, `Component ID: ${node.id}`, "vobs-devtools-code");
|
|
2922
|
+
appendText(row, "Recent updates:", "vobs-devtools-code");
|
|
2923
|
+
appendUpdateLinks(row, node.recentUpdates, onFocus);
|
|
2924
|
+
if (node.domUpdates > 0) {
|
|
2925
|
+
appendText(row, "DOM results:", "vobs-devtools-code");
|
|
2926
|
+
for (const updateId of node.recentUpdates) {
|
|
2927
|
+
const update = snapshot.updates.find((item) => item.id === updateId);
|
|
2928
|
+
for (const domUpdate of update?.domUpdates ?? []) {
|
|
2929
|
+
const operation = domUpdate.key ? `${domUpdate.operation}.${domUpdate.key}` : domUpdate.operation;
|
|
2930
|
+
appendText(row, `${operation} ${domUpdate.target}`, "vobs-devtools-muted");
|
|
2931
|
+
}
|
|
2932
|
+
}
|
|
2933
|
+
}
|
|
2934
|
+
if (node.children.length > 0) {
|
|
2935
|
+
appendText(row, "Children:", "vobs-devtools-code");
|
|
2936
|
+
for (const child of node.children) insertBefore(row, renderComponentSummary(child, snapshot, selection, onFocus), null);
|
|
2937
|
+
}
|
|
2938
|
+
return row;
|
|
2939
|
+
}
|
|
2940
|
+
__name(renderComponentSummary, "renderComponentSummary");
|
|
2941
|
+
function formatValue(value) {
|
|
2942
|
+
if (typeof value === "string") return value;
|
|
2943
|
+
try {
|
|
2944
|
+
return JSON.stringify(value) ?? String(value);
|
|
2945
|
+
} catch {
|
|
2946
|
+
return String(value);
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2949
|
+
__name(formatValue, "formatValue");
|
|
2950
|
+
function renderValuePair(label, previousValue, nextValue) {
|
|
2951
|
+
const root = createElement("div");
|
|
2952
|
+
setAttribute(root, "class", `vobs-devtools-value-pair${label ? "" : " vobs-devtools-value-pair--compact"}`);
|
|
2953
|
+
const distinctMode = state(Boolean(label));
|
|
2954
|
+
root.addEventListener("click", (event) => event.stopPropagation());
|
|
2955
|
+
root.addEventListener("pointerdown", (event) => event.stopPropagation());
|
|
2956
|
+
if (label) {
|
|
2957
|
+
const title = createElement("div");
|
|
2958
|
+
setAttribute(title, "class", "vobs-devtools-value-pair__title");
|
|
2959
|
+
appendText(title, label);
|
|
2960
|
+
const toggle = createElement("button");
|
|
2961
|
+
setAttribute(toggle, "class", "vobs-devtools-distinct-toggle is-active");
|
|
2962
|
+
setAttribute(toggle, "type", "button");
|
|
2963
|
+
setAttribute(toggle, "aria-pressed", "true");
|
|
2964
|
+
setAttribute(toggle, "title", "Show only values that changed");
|
|
2965
|
+
insertBefore(toggle, createText("distinct"), null);
|
|
2966
|
+
toggle.addEventListener("click", (event) => {
|
|
2967
|
+
event.stopPropagation();
|
|
2968
|
+
const enabled = !distinctMode.value;
|
|
2969
|
+
distinctMode.value = enabled;
|
|
2970
|
+
setAttribute(toggle, "class", `vobs-devtools-distinct-toggle${enabled ? " is-active" : ""}`);
|
|
2971
|
+
setAttribute(toggle, "aria-pressed", enabled ? "true" : "false");
|
|
2972
|
+
setAttribute(toggle, "title", enabled ? "Show only values that changed" : "Show complete values");
|
|
2973
|
+
});
|
|
2974
|
+
insertBefore(title, toggle, null);
|
|
2975
|
+
insertBefore(root, title, null);
|
|
2976
|
+
}
|
|
2977
|
+
insertDynamic(root, null, () => {
|
|
2978
|
+
const distinct = distinctMode.value;
|
|
2979
|
+
const difference = distinct ? createDistinctValuePair(previousValue, nextValue) : null;
|
|
2980
|
+
const before = difference?.before ?? { value: previousValue, hasDifference: true };
|
|
2981
|
+
const after = difference?.after ?? { value: nextValue, hasDifference: true };
|
|
2982
|
+
return createFragment((parent, anchor) => {
|
|
2983
|
+
insertBefore(parent, renderValueTree("Before", before.value, Boolean(label), distinct && !before.hasDifference ? "No differing fields" : void 0), anchor);
|
|
2984
|
+
insertBefore(parent, renderValueTree("After", after.value, Boolean(label), distinct && !after.hasDifference ? "No differing fields" : void 0), anchor);
|
|
2985
|
+
});
|
|
2986
|
+
});
|
|
2987
|
+
return root;
|
|
2988
|
+
}
|
|
2989
|
+
__name(renderValuePair, "renderValuePair");
|
|
2990
|
+
function renderValueTree(label, value, expanded, emptyMessage) {
|
|
2991
|
+
const root = createElement("section");
|
|
2992
|
+
setAttribute(root, "class", "vobs-devtools-value-inspector");
|
|
2993
|
+
root.addEventListener("click", (event) => event.stopPropagation());
|
|
2994
|
+
root.addEventListener("pointerdown", (event) => event.stopPropagation());
|
|
2995
|
+
if (hasExpandableEntries(value)) {
|
|
2996
|
+
const controls = createElement("div");
|
|
2997
|
+
setAttribute(controls, "class", "vobs-devtools-value-inspector__controls");
|
|
2998
|
+
insertBefore(controls, createComponent(Button, {
|
|
2999
|
+
variant: "ghost",
|
|
3000
|
+
iconOnly: true,
|
|
3001
|
+
icon: createComponent(Icon, { name: "plus" }),
|
|
3002
|
+
"aria-label": `Expand all ${label} values`,
|
|
3003
|
+
title: `Expand all ${label} values`,
|
|
3004
|
+
onClick: /* @__PURE__ */ __name((event) => {
|
|
3005
|
+
event.stopPropagation();
|
|
3006
|
+
for (const node of root.querySelectorAll(".vobs-devtools-value-tree")) setAttribute(node, "data-expanded", "true");
|
|
3007
|
+
}, "onClick")
|
|
3008
|
+
}), null);
|
|
3009
|
+
insertBefore(controls, createComponent(Button, {
|
|
3010
|
+
variant: "ghost",
|
|
3011
|
+
iconOnly: true,
|
|
3012
|
+
icon: createComponent(Icon, { name: "minus" }),
|
|
3013
|
+
"aria-label": `Collapse all ${label} values`,
|
|
3014
|
+
title: `Collapse all ${label} values`,
|
|
3015
|
+
onClick: /* @__PURE__ */ __name((event) => {
|
|
3016
|
+
event.stopPropagation();
|
|
3017
|
+
for (const node of root.querySelectorAll(".vobs-devtools-value-tree")) setAttribute(node, "data-expanded", "false");
|
|
3018
|
+
}, "onClick")
|
|
3019
|
+
}), null);
|
|
3020
|
+
insertBefore(root, controls, null);
|
|
3021
|
+
}
|
|
3022
|
+
const tree = createElement("div");
|
|
3023
|
+
setAttribute(tree, "class", "vobs-devtools-value-tree-root");
|
|
3024
|
+
setAttribute(tree, "role", "tree");
|
|
3025
|
+
setAttribute(tree, "aria-label", `${label} value`);
|
|
3026
|
+
if (emptyMessage) appendText(tree, emptyMessage, "vobs-devtools-value-tree__empty");
|
|
3027
|
+
else insertBefore(tree, renderInspectableValue(label, value, expanded), null);
|
|
3028
|
+
insertBefore(root, tree, null);
|
|
3029
|
+
return root;
|
|
3030
|
+
}
|
|
3031
|
+
__name(renderValueTree, "renderValueTree");
|
|
3032
|
+
var MISSING_VALUE = Symbol("missing diagnostic value");
|
|
3033
|
+
function createDistinctValuePair(before, after) {
|
|
3034
|
+
return projectDistinctValues(before, after);
|
|
3035
|
+
}
|
|
3036
|
+
__name(createDistinctValuePair, "createDistinctValuePair");
|
|
3037
|
+
function projectDistinctValues(before, after) {
|
|
3038
|
+
if (areValuesEqual(before, after)) {
|
|
3039
|
+
return {
|
|
3040
|
+
before: { value: before, hasDifference: false },
|
|
3041
|
+
after: { value: after, hasDifference: false }
|
|
3042
|
+
};
|
|
3043
|
+
}
|
|
3044
|
+
if (!isExpandableValue(before) || !isExpandableValue(after)) {
|
|
3045
|
+
return {
|
|
3046
|
+
before: { value: before, hasDifference: true },
|
|
3047
|
+
after: { value: after, hasDifference: true }
|
|
3048
|
+
};
|
|
3049
|
+
}
|
|
3050
|
+
if (Array.isArray(before) && Array.isArray(after)) {
|
|
3051
|
+
const beforeProjection = new Array(before.length);
|
|
3052
|
+
const afterProjection = new Array(after.length);
|
|
3053
|
+
for (let index = 0; index < Math.max(before.length, after.length); index++) {
|
|
3054
|
+
const child = projectDistinctValues(
|
|
3055
|
+
index in before ? before[index] : MISSING_VALUE,
|
|
3056
|
+
index in after ? after[index] : MISSING_VALUE
|
|
3057
|
+
);
|
|
3058
|
+
if (child.before.value !== MISSING_VALUE) beforeProjection[index] = child.before.value;
|
|
3059
|
+
if (child.after.value !== MISSING_VALUE) afterProjection[index] = child.after.value;
|
|
3060
|
+
}
|
|
3061
|
+
return {
|
|
3062
|
+
before: { value: beforeProjection, hasDifference: valueEntries(beforeProjection).length > 0 },
|
|
3063
|
+
after: { value: afterProjection, hasDifference: valueEntries(afterProjection).length > 0 }
|
|
3064
|
+
};
|
|
3065
|
+
}
|
|
3066
|
+
if (!Array.isArray(before) && !Array.isArray(after)) {
|
|
3067
|
+
const beforeProjection = {};
|
|
3068
|
+
const afterProjection = {};
|
|
3069
|
+
const beforeObject = before;
|
|
3070
|
+
const afterObject = after;
|
|
3071
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(beforeObject), ...Object.keys(afterObject)]);
|
|
3072
|
+
for (const key of keys) {
|
|
3073
|
+
const child = projectDistinctValues(
|
|
3074
|
+
Object.prototype.hasOwnProperty.call(beforeObject, key) ? beforeObject[key] : MISSING_VALUE,
|
|
3075
|
+
Object.prototype.hasOwnProperty.call(afterObject, key) ? afterObject[key] : MISSING_VALUE
|
|
3076
|
+
);
|
|
3077
|
+
if (child.before.value !== MISSING_VALUE) beforeProjection[key] = child.before.value;
|
|
3078
|
+
if (child.after.value !== MISSING_VALUE) afterProjection[key] = child.after.value;
|
|
3079
|
+
}
|
|
3080
|
+
return {
|
|
3081
|
+
before: { value: beforeProjection, hasDifference: Object.keys(beforeProjection).length > 0 },
|
|
3082
|
+
after: { value: afterProjection, hasDifference: Object.keys(afterProjection).length > 0 }
|
|
3083
|
+
};
|
|
3084
|
+
}
|
|
3085
|
+
return {
|
|
3086
|
+
before: { value: before, hasDifference: true },
|
|
3087
|
+
after: { value: after, hasDifference: true }
|
|
3088
|
+
};
|
|
3089
|
+
}
|
|
3090
|
+
__name(projectDistinctValues, "projectDistinctValues");
|
|
3091
|
+
function areValuesEqual(before, after, seen = /* @__PURE__ */ new WeakMap()) {
|
|
3092
|
+
if (Object.is(before, after)) return true;
|
|
3093
|
+
if (!isExpandableValue(before) || !isExpandableValue(after)) return false;
|
|
3094
|
+
if (Array.isArray(before) !== Array.isArray(after)) return false;
|
|
3095
|
+
if (Object.prototype.toString.call(before) !== Object.prototype.toString.call(after)) return false;
|
|
3096
|
+
const previousPairs = seen.get(before);
|
|
3097
|
+
if (previousPairs?.has(after)) return true;
|
|
3098
|
+
if (previousPairs) previousPairs.add(after);
|
|
3099
|
+
else seen.set(before, new WeakSet([after]));
|
|
3100
|
+
const beforeKeys = Object.keys(before);
|
|
3101
|
+
const afterKeys = Object.keys(after);
|
|
3102
|
+
if (beforeKeys.length !== afterKeys.length) return false;
|
|
3103
|
+
const beforeObject = before;
|
|
3104
|
+
const afterObject = after;
|
|
3105
|
+
return beforeKeys.every((key) => Object.prototype.hasOwnProperty.call(afterObject, key) && areValuesEqual(beforeObject[key], afterObject[key], seen));
|
|
3106
|
+
}
|
|
3107
|
+
__name(areValuesEqual, "areValuesEqual");
|
|
3108
|
+
function renderInspectableValue(label, value, expanded = false, ancestors = []) {
|
|
3109
|
+
if (!hasExpandableEntries(value) || ancestors.includes(value)) {
|
|
3110
|
+
const row = createElement("div");
|
|
3111
|
+
setAttribute(row, "class", "vobs-devtools-value-tree__leaf");
|
|
3112
|
+
setAttribute(row, "role", "treeitem");
|
|
3113
|
+
appendText(row, label, "vobs-devtools-value-field__label");
|
|
3114
|
+
appendText(row, ancestors.includes(value) ? "[Circular]" : previewValue(value), "vobs-devtools-code");
|
|
3115
|
+
return row;
|
|
3116
|
+
}
|
|
3117
|
+
const root = createElement("div");
|
|
3118
|
+
setAttribute(root, "class", "vobs-devtools-value-tree");
|
|
3119
|
+
setAttribute(root, "role", "treeitem");
|
|
3120
|
+
setAttribute(root, "data-expanded", expanded ? "true" : "false");
|
|
3121
|
+
const summary = createElement("button");
|
|
3122
|
+
setAttribute(summary, "class", "vobs-devtools-value-tree__summary");
|
|
3123
|
+
setAttribute(summary, "type", "button");
|
|
3124
|
+
setAttribute(summary, "aria-expanded", expanded ? "true" : "false");
|
|
3125
|
+
setAttribute(summary, "title", `Expand ${label}`);
|
|
3126
|
+
const toggleExpanded = /* @__PURE__ */ __name(() => {
|
|
3127
|
+
const expanded2 = root.getAttribute("data-expanded") !== "true";
|
|
3128
|
+
setAttribute(root, "data-expanded", expanded2 ? "true" : "false");
|
|
3129
|
+
setAttribute(summary, "aria-expanded", expanded2 ? "true" : "false");
|
|
3130
|
+
setAttribute(summary, "title", `${expanded2 ? "Collapse" : "Expand"} ${label}`);
|
|
3131
|
+
}, "toggleExpanded");
|
|
3132
|
+
summary.addEventListener("pointerdown", (event) => {
|
|
3133
|
+
event.preventDefault();
|
|
3134
|
+
event.stopPropagation();
|
|
3135
|
+
toggleExpanded();
|
|
3136
|
+
});
|
|
3137
|
+
summary.addEventListener("keydown", (event) => {
|
|
3138
|
+
const keyboardEvent = event;
|
|
3139
|
+
if (keyboardEvent.key !== "Enter" && keyboardEvent.key !== " ") return;
|
|
3140
|
+
event.preventDefault();
|
|
3141
|
+
event.stopPropagation();
|
|
3142
|
+
toggleExpanded();
|
|
3143
|
+
});
|
|
3144
|
+
appendText(summary, label, "vobs-devtools-value-field__label");
|
|
3145
|
+
appendText(summary, previewValue(value), "vobs-devtools-code");
|
|
3146
|
+
insertBefore(root, summary, null);
|
|
3147
|
+
const children = createElement("div");
|
|
3148
|
+
setAttribute(children, "class", "vobs-devtools-value-tree__children");
|
|
3149
|
+
setAttribute(children, "role", "group");
|
|
3150
|
+
for (const [key, child] of valueEntries(value)) {
|
|
3151
|
+
insertBefore(children, renderInspectableValue(key, child, false, [...ancestors, value]), null);
|
|
3152
|
+
}
|
|
3153
|
+
insertBefore(root, children, null);
|
|
3154
|
+
return root;
|
|
3155
|
+
}
|
|
3156
|
+
__name(renderInspectableValue, "renderInspectableValue");
|
|
3157
|
+
function isExpandableValue(value) {
|
|
3158
|
+
return typeof value === "object" && value !== null;
|
|
3159
|
+
}
|
|
3160
|
+
__name(isExpandableValue, "isExpandableValue");
|
|
3161
|
+
function hasExpandableEntries(value) {
|
|
3162
|
+
return isExpandableValue(value) && valueEntries(value).length > 0;
|
|
3163
|
+
}
|
|
3164
|
+
__name(hasExpandableEntries, "hasExpandableEntries");
|
|
3165
|
+
function valueEntries(value) {
|
|
3166
|
+
if (Array.isArray(value)) return value.slice(0, 100).map((item, index) => [`[${index}]`, item]);
|
|
3167
|
+
return Object.entries(value).slice(0, 100);
|
|
3168
|
+
}
|
|
3169
|
+
__name(valueEntries, "valueEntries");
|
|
3170
|
+
function previewValue(value) {
|
|
3171
|
+
if (value === void 0) return "undefined";
|
|
3172
|
+
if (value === null) return "null";
|
|
3173
|
+
if (typeof value === "string") return value;
|
|
3174
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
|
|
3175
|
+
if (Array.isArray(value)) return `Array (${value.length} items)`;
|
|
3176
|
+
if (typeof value === "object") return `Object (${Object.keys(value).length} fields)`;
|
|
3177
|
+
return String(value);
|
|
3178
|
+
}
|
|
3179
|
+
__name(previewValue, "previewValue");
|
|
3180
|
+
|
|
3181
|
+
export { DevToolsPanel, DevToolsToolbar, readDevToolsSnapshot };
|
|
3182
|
+
//# sourceMappingURL=panel.js.map
|
|
3183
|
+
//# sourceMappingURL=panel.js.map
|