@fluixi/devtools 0.2.0-alpha.3 → 0.2.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/dist/callsite.cjs +72 -0
  2. package/dist/callsite.d.ts +1 -1
  3. package/dist/callsite.js +1 -1
  4. package/dist/callsite.mjs +51 -0
  5. package/dist/change-view.cjs +134 -0
  6. package/dist/change-view.js +2 -2
  7. package/dist/change-view.mjs +111 -0
  8. package/dist/copy.cjs +63 -0
  9. package/dist/copy.mjs +42 -0
  10. package/dist/describe.cjs +55 -0
  11. package/dist/describe.js +2 -2
  12. package/dist/describe.mjs +34 -0
  13. package/dist/detail-panel.cjs +307 -0
  14. package/dist/detail-panel.d.ts +1 -1
  15. package/dist/detail-panel.d.ts.map +1 -1
  16. package/dist/detail-panel.js +1 -1
  17. package/dist/detail-panel.mjs +284 -0
  18. package/dist/diff.cjs +225 -0
  19. package/dist/diff.js +1 -1
  20. package/dist/diff.mjs +202 -0
  21. package/dist/dom.cjs +204 -0
  22. package/dist/dom.mjs +183 -0
  23. package/dist/export.cjs +221 -0
  24. package/dist/export.d.ts +2 -2
  25. package/dist/export.d.ts.map +1 -1
  26. package/dist/export.js +1 -1
  27. package/dist/export.mjs +209 -0
  28. package/dist/float.cjs +232 -0
  29. package/dist/float.d.ts +1 -1
  30. package/dist/float.js +3 -3
  31. package/dist/float.mjs +211 -0
  32. package/dist/format.cjs +175 -0
  33. package/dist/format.js +3 -3
  34. package/dist/format.mjs +154 -0
  35. package/dist/graph-view.cjs +893 -0
  36. package/dist/graph-view.mjs +870 -0
  37. package/dist/highlight.cjs +140 -0
  38. package/dist/highlight.mjs +119 -0
  39. package/dist/history.cjs +95 -0
  40. package/dist/history.d.ts +2 -2
  41. package/dist/history.js +2 -2
  42. package/dist/history.mjs +74 -0
  43. package/dist/hook.cjs +1562 -0
  44. package/dist/hook.d.ts +3 -3
  45. package/dist/hook.js +6 -6
  46. package/dist/hook.mjs +1553 -0
  47. package/dist/index.cjs +4552 -0
  48. package/dist/index.mjs +4544 -0
  49. package/dist/inspector.cjs +688 -0
  50. package/dist/inspector.d.ts +2 -2
  51. package/dist/inspector.js +7 -7
  52. package/dist/inspector.mjs +676 -0
  53. package/dist/instrument.cjs +497 -0
  54. package/dist/instrument.mjs +487 -0
  55. package/dist/kind-filter.cjs +172 -0
  56. package/dist/kind-filter.d.ts +2 -2
  57. package/dist/kind-filter.js +1 -1
  58. package/dist/kind-filter.mjs +151 -0
  59. package/dist/menu.cjs +141 -0
  60. package/dist/menu.mjs +120 -0
  61. package/dist/observe.cjs +1352 -0
  62. package/dist/observe.mjs +1345 -0
  63. package/dist/palette.cjs +52 -0
  64. package/dist/palette.mjs +31 -0
  65. package/dist/path.cjs +45 -0
  66. package/dist/path.d.ts +2 -2
  67. package/dist/path.js +2 -2
  68. package/dist/path.mjs +24 -0
  69. package/dist/plugin.cjs +87 -0
  70. package/dist/plugin.mjs +66 -0
  71. package/dist/plugins/context.cjs +98 -0
  72. package/dist/plugins/context.mjs +75 -0
  73. package/dist/plugins/directives.cjs +98 -0
  74. package/dist/plugins/directives.mjs +75 -0
  75. package/dist/plugins/index.cjs +162 -0
  76. package/dist/plugins/index.mjs +140 -0
  77. package/dist/source.cjs +111 -0
  78. package/dist/source.d.ts +2 -2
  79. package/dist/source.js +4 -4
  80. package/dist/source.mjs +90 -0
  81. package/dist/timeline.cjs +350 -0
  82. package/dist/timeline.js +3 -3
  83. package/dist/timeline.mjs +327 -0
  84. package/dist/tree.cjs +574 -0
  85. package/dist/tree.mjs +551 -0
  86. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  87. package/dist/value-pane.cjs +223 -0
  88. package/dist/value-pane.mjs +200 -0
  89. package/dist/wire.cjs +109 -0
  90. package/dist/wire.mjs +89 -0
  91. package/package.json +19 -6
package/dist/tree.mjs ADDED
@@ -0,0 +1,551 @@
1
+ // src/plugin.ts
2
+ var plugins = [];
3
+ function pluginElementBadge(extra) {
4
+ if (!extra) return void 0;
5
+ for (const plugin of plugins) {
6
+ try {
7
+ const badge = plugin.elementBadge?.(extra);
8
+ if (badge) return badge;
9
+ } catch {
10
+ }
11
+ }
12
+ return void 0;
13
+ }
14
+ function pluginBadge(node) {
15
+ for (const plugin of plugins) {
16
+ try {
17
+ const badge = plugin.badge?.(node);
18
+ if (badge) return badge;
19
+ } catch {
20
+ }
21
+ }
22
+ return void 0;
23
+ }
24
+
25
+ // src/palette.ts
26
+ var KIND_COLOR = {
27
+ state: "#34d399",
28
+ memo: "#a78bfa",
29
+ effect: "#fbbf24",
30
+ store: "#38bdf8",
31
+ resource: "#fb7185",
32
+ component: "#f0abfc",
33
+ provider: "#fb923c",
34
+ control: "#22d3ee",
35
+ router: "#818cf8",
36
+ handler: "#f472b6",
37
+ context: "#a3e635",
38
+ directive: "#5eead4",
39
+ binding: "#5eead4",
40
+ setter: "#fb7185",
41
+ group: "#8a90a2",
42
+ element: "#8a90a2"
43
+ };
44
+ var kindVar = (kind) => `--fx-kind-${kind}`;
45
+ var kindColor = (kind) => `var(${kindVar(kind)}, ${KIND_COLOR[kind]})`;
46
+ var KINDS = Object.keys(KIND_COLOR);
47
+ function kindRules(selector, property) {
48
+ return KINDS.map((kind) => `${selector(kind)} { ${property}: ${kindColor(kind)}; }`).join("\n");
49
+ }
50
+
51
+ // src/format.ts
52
+ function shorten(text, limit = 18) {
53
+ return text.length > limit ? `${text.slice(0, limit - 1)}…` : text;
54
+ }
55
+
56
+ // src/tree.ts
57
+ var TREE_KINDS = /* @__PURE__ */ new Set([
58
+ "component",
59
+ "control",
60
+ "router",
61
+ "handler",
62
+ // A component a plugin recognised as providing a context. Still a tag the author wrote,
63
+ // so leaving it out took it and everything it rendered out of the tree.
64
+ "provider"
65
+ ]);
66
+ function inPageOrder(nodes) {
67
+ const slots = [];
68
+ const placed = [];
69
+ nodes.forEach((node, at) => {
70
+ if (node.order !== void 0) {
71
+ slots.push(at);
72
+ placed.push(node);
73
+ }
74
+ });
75
+ if (placed.length < 2) return nodes;
76
+ placed.sort((a, b) => a.order - b.order);
77
+ const out = nodes.slice();
78
+ slots.forEach((slot, i) => out[slot] = placed[i]);
79
+ return out;
80
+ }
81
+ var badges = /* @__PURE__ */ new WeakMap();
82
+ function badgeOf(node) {
83
+ if (!badges.has(node)) badges.set(node, pluginBadge(node));
84
+ return badges.get(node);
85
+ }
86
+ function componentTree(graph, options = {}) {
87
+ const wanted = (node) => TREE_KINDS.has(node.kind) || options.values === true && node.authored !== false;
88
+ const tagged = inPageOrder([...graph.values()].filter(wanted).sort((a, b) => a.id - b.id));
89
+ const made = /* @__PURE__ */ new Map();
90
+ for (const node of tagged) {
91
+ made.set(node.id, {
92
+ id: node.id,
93
+ label: node.label,
94
+ kind: node.kind,
95
+ children: [],
96
+ ...TREE_KINDS.has(node.kind) ? {} : { value: true },
97
+ ...node.lazy ? { lazy: true } : {},
98
+ ...badgeOf(node) ? { badge: badgeOf(node) } : {}
99
+ });
100
+ }
101
+ const owner = (node) => {
102
+ const seen = /* @__PURE__ */ new Set([node.id]);
103
+ let at = node.createdIn;
104
+ while (at !== void 0 && !seen.has(at)) {
105
+ seen.add(at);
106
+ const found = made.get(at);
107
+ if (found) return found;
108
+ at = graph.get(at)?.createdIn;
109
+ }
110
+ return void 0;
111
+ };
112
+ const roots = [];
113
+ for (const node of tagged) {
114
+ const parent = owner(node);
115
+ if (parent) parent.children.push(made.get(node.id));
116
+ else roots.push(made.get(node.id));
117
+ }
118
+ const term = options.filter?.trim().toLowerCase();
119
+ return term ? keep(roots, term) : roots;
120
+ }
121
+ function keep(nodes, term) {
122
+ const out = [];
123
+ for (const node of nodes) {
124
+ const children = keep(node.children, term);
125
+ const hit = node.label.toLowerCase().includes(term);
126
+ if (hit || children.length) out.push({ ...node, children: hit ? node.children : children });
127
+ }
128
+ return out;
129
+ }
130
+ function idsIn(nodes) {
131
+ const out = [];
132
+ const walk = (list) => {
133
+ for (const node of list) {
134
+ out.push(node.id);
135
+ walk(node.children);
136
+ }
137
+ };
138
+ walk(nodes);
139
+ return out;
140
+ }
141
+ var escape = (text) => text.replace(/[&<>"]/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[c]);
142
+ function createComponentTree(host, options = {}) {
143
+ const empty = options.empty ?? "nothing rendered yet";
144
+ const shut = /* @__PURE__ */ new Set();
145
+ let signature = "";
146
+ const defaulted = /* @__PURE__ */ new Set();
147
+ let marked = null;
148
+ let markedKey = null;
149
+ let values = options.values === true;
150
+ let filter = "";
151
+ const doc = host.ownerDocument;
152
+ const bar = doc.createElement("label");
153
+ bar.className = "fx-tree-bar";
154
+ const box = doc.createElement("input");
155
+ box.type = "checkbox";
156
+ box.checked = values;
157
+ bar.append(box, doc.createTextNode("values"));
158
+ bar.title = "List the signals and memos each tag declares";
159
+ const search = doc.createElement("input");
160
+ search.type = "search";
161
+ search.className = "fx-tree-search";
162
+ search.placeholder = "filter by name";
163
+ search.addEventListener("input", () => {
164
+ filter = search.value;
165
+ signature = "";
166
+ });
167
+ const list = doc.createElement("div");
168
+ list.className = "fx-tree-list";
169
+ host.replaceChildren(bar, search, list);
170
+ let last = null;
171
+ box.addEventListener("change", () => {
172
+ values = box.checked;
173
+ signature = "";
174
+ if (last) api.render(last.graph, last.selected);
175
+ });
176
+ const row = (node, depth) => {
177
+ const has = node.children.length > 0;
178
+ const open = has && !shut.has(node.key);
179
+ const twist = has ? open ? "▾" : "▸" : node.prop ? "" : "·";
180
+ const tag = node.props ? `<span class="fx-tree-props-label">props</span><span class="fx-tree-props-count">${node.children.length}</span>` : node.prop ? `<span class="fx-tree-prop-name">${escape(node.prop.name)}</span>${node.prop.value === void 0 ? "" : `<span class="fx-tree-prop-value">${escape(shorten(node.prop.value, 44))}</span>`}` : node.value ? escape(node.label) : has ? `&lt;${escape(node.label)}&gt;` : `&lt;${escape(node.label)} /&gt;`;
181
+ const count = has && !open && !node.props ? `<span class="fx-tree-count">${node.children.length}</span>` : "";
182
+ const chunk = node.lazy ? '<span class="fx-tree-lazy" title="loaded as its own chunk">lazy</span>' : "";
183
+ const mark = node.badge ? `<span class="fx-tree-plugin" title="${escape(node.badge)}">${escape(node.badge)}</span>` : "";
184
+ return `<div class="fx-tree-row n-${node.kind}${node.value ? " is-value" : ""}${node.prop ? " is-prop" : ""}${node.props ? " is-props" : ""}" data-key="${escape(node.key)}"${node.id !== void 0 ? ` data-id="${node.id}"` : ""} style="--depth:${depth}"><button type="button" class="fx-tree-twist" data-twist="${escape(node.key)}"${has ? "" : ' tabindex="-1"'}>${twist}</button><span class="fx-tree-tag"${node.prop?.value ? ` title="${escape(node.prop.name)}=${escape(node.prop.value)}"` : ""}>${tag}</span>${mark}${chunk}${count}</div>` + (open ? node.children.map((child) => row(child, depth + 1)).join("") : "");
185
+ };
186
+ const pickOf = (rowEl) => {
187
+ const found = shown.get(rowEl.dataset.key ?? "");
188
+ if (!found || found.kind !== "element") return void 0;
189
+ return {
190
+ key: found.key,
191
+ label: found.label,
192
+ ...found.owner !== void 0 ? { owner: found.owner } : {},
193
+ ...found.writes?.length ? { writes: found.writes } : {},
194
+ ...found.at ? { at: found.at } : {},
195
+ ...found.extra ? { extra: found.extra } : {},
196
+ ...found.element ? { element: found.element } : {}
197
+ };
198
+ };
199
+ const onClick = (event) => {
200
+ const target = event.target;
201
+ const twist = target?.closest?.("[data-twist]");
202
+ if (twist) {
203
+ const key = twist.dataset.twist ?? "";
204
+ if (shut.has(key)) shut.delete(key);
205
+ else shut.add(key);
206
+ signature = "";
207
+ event.stopPropagation();
208
+ return;
209
+ }
210
+ const rowEl = target?.closest?.(".fx-tree-row");
211
+ if (!rowEl) return;
212
+ if (rowEl.dataset.id) {
213
+ markedKey = null;
214
+ options.onSelect?.(Number(rowEl.dataset.id));
215
+ return;
216
+ }
217
+ const held = shown.get(rowEl.dataset.key ?? "");
218
+ if (held?.props) {
219
+ if (shut.has(held.key)) shut.delete(held.key);
220
+ else shut.add(held.key);
221
+ signature = "";
222
+ if (last) api.render(last.graph, last.selected);
223
+ return;
224
+ }
225
+ if (held?.prop) {
226
+ if (held.owner === void 0) return;
227
+ markedKey = held.key;
228
+ paint();
229
+ options.onSelect?.(held.owner);
230
+ return;
231
+ }
232
+ const pick = pickOf(rowEl);
233
+ if (!pick) return;
234
+ markedKey = pick.key;
235
+ paint();
236
+ options.onPick?.(pick);
237
+ };
238
+ const onDouble = (event) => {
239
+ const rowEl = event.target?.closest?.(".fx-tree-row");
240
+ if (!rowEl) return;
241
+ if (rowEl.dataset.id) {
242
+ options.onReveal?.(Number(rowEl.dataset.id));
243
+ return;
244
+ }
245
+ const pick = pickOf(rowEl);
246
+ if (pick) options.onRevealPick?.(pick);
247
+ };
248
+ let shown = /* @__PURE__ */ new Map();
249
+ const onOver = (event) => {
250
+ const rowEl = event.target?.closest?.(".fx-tree-row");
251
+ const found = rowEl ? shown.get(rowEl.dataset.key ?? "") : void 0;
252
+ if (!found) {
253
+ options.onHover?.(null);
254
+ return;
255
+ }
256
+ options.onHover?.(found.id ?? null, found.element, found.id === void 0 ? found.key : void 0);
257
+ };
258
+ const onOut = () => options.onHover?.(null);
259
+ host.addEventListener("click", onClick);
260
+ host.addEventListener("dblclick", onDouble);
261
+ if (options.onHover) {
262
+ host.addEventListener("pointermove", onOver);
263
+ host.addEventListener("pointerleave", onOut);
264
+ }
265
+ const paint = () => {
266
+ for (const el of list.querySelectorAll(".fx-tree-row")) {
267
+ const row2 = el;
268
+ const id = row2.dataset.id;
269
+ const on = id !== void 0 ? Number(id) === marked : row2.dataset.key === markedKey;
270
+ el.classList.toggle("on", on);
271
+ }
272
+ };
273
+ function rowsFor(nodes, graph) {
274
+ const byId = /* @__PURE__ */ new Map();
275
+ const build = (node) => {
276
+ const written = values ? graph.get(node.id)?.props ?? [] : [];
277
+ const listed = written.map((p, i) => ({
278
+ key: `${node.id}=${i}`,
279
+ label: p.name,
280
+ kind: node.kind,
281
+ children: [],
282
+ prop: { name: p.name, ...p.value === void 0 ? {} : { value: p.value } },
283
+ owner: node.id,
284
+ ...p.at?.line === void 0 ? {} : { at: { file: p.at.file ?? "", line: p.at.line, column: p.at.column ?? 0 } }
285
+ }));
286
+ const group = `${node.id}=props`;
287
+ if (listed.length && !defaulted.has(group)) {
288
+ defaulted.add(group);
289
+ shut.add(group);
290
+ }
291
+ const props = listed.length ? [{ key: group, label: "props", kind: node.kind, children: listed, props: true, owner: node.id }] : [];
292
+ const row2 = {
293
+ key: String(node.id),
294
+ label: node.label,
295
+ kind: node.kind,
296
+ id: node.id,
297
+ children: [...props, ...node.children.map(build)],
298
+ ...node.value ? { value: true } : {},
299
+ ...node.lazy ? { lazy: true } : {},
300
+ ...node.badge ? { badge: node.badge } : {}
301
+ };
302
+ byId.set(node.id, row2);
303
+ return row2;
304
+ };
305
+ const roots = nodes.map(build);
306
+ const domFor = options.domFor;
307
+ if (!domFor) return roots;
308
+ const placed = /* @__PURE__ */ new Set();
309
+ const done = /* @__PURE__ */ new Set();
310
+ const uses = /* @__PURE__ */ new Map();
311
+ const tally = (nodes2) => {
312
+ for (const node of nodes2) {
313
+ if (node.owner !== void 0) uses.set(node.owner, (uses.get(node.owner) ?? 0) + 1);
314
+ tally(node.children);
315
+ }
316
+ };
317
+ for (const row2 of byId.values()) if (row2.id !== void 0) tally(domFor(row2.id));
318
+ const readerOf = (id, skip) => {
319
+ const drawn = (from) => {
320
+ const seen = /* @__PURE__ */ new Set();
321
+ let at = from;
322
+ while (at !== void 0 && !seen.has(at)) {
323
+ seen.add(at);
324
+ const row2 = byId.get(at);
325
+ if (row2 && !row2.value && row2 !== skip) return row2;
326
+ at = graph.get(at)?.createdIn;
327
+ }
328
+ return void 0;
329
+ };
330
+ let best;
331
+ let deepest = -1;
332
+ for (const [nodeId, node] of graph) {
333
+ if (nodeId === id || !node.deps.has(id)) continue;
334
+ const row2 = drawn(nodeId);
335
+ if (!row2 || row2.id === void 0) continue;
336
+ const depth = graph.get(row2.id)?.depth ?? 0;
337
+ if (depth >= deepest) {
338
+ deepest = depth;
339
+ best = row2;
340
+ }
341
+ }
342
+ return best;
343
+ };
344
+ const again = (row2, key) => ({
345
+ ...row2,
346
+ key,
347
+ children: row2.children.map((child, i) => again(child, `${key}/${i}`))
348
+ });
349
+ const expand = (row2) => {
350
+ if (row2.value || row2.id === void 0) return row2;
351
+ if (done.has(row2)) return row2;
352
+ done.add(row2);
353
+ const dom = domFor(row2.id);
354
+ if (!dom.length) {
355
+ row2.children = row2.children.map(expand);
356
+ return row2;
357
+ }
358
+ const walk = (node, key) => {
359
+ const owner = node.owner === void 0 ? void 0 : byId.get(node.owner);
360
+ if (owner && owner !== row2) {
361
+ if (done.has(owner)) {
362
+ const count = uses.get(node.owner) ?? 0;
363
+ return count > 1 ? again(owner, key) : void 0;
364
+ }
365
+ placed.add(owner);
366
+ return expand(owner);
367
+ }
368
+ const kids = [];
369
+ for (const id of node.writes ?? []) {
370
+ const value = byId.get(id);
371
+ if (!value?.value || placed.has(value)) continue;
372
+ placed.add(value);
373
+ kids.push(value);
374
+ }
375
+ for (const id of node.inside ?? []) {
376
+ const tag = byId.get(id);
377
+ if (!tag || tag === row2 || placed.has(tag) || done.has(tag)) continue;
378
+ placed.add(tag);
379
+ kids.push(expand(tag));
380
+ }
381
+ node.children.forEach((child, i) => {
382
+ const kid = walk(child, `${key}/${i}`);
383
+ if (kid) kids.push(kid);
384
+ });
385
+ return {
386
+ key,
387
+ label: node.label,
388
+ kind: "element",
389
+ children: kids,
390
+ owner: row2.id,
391
+ ...node.writes?.length ? { writes: node.writes } : {},
392
+ ...node.at ? { at: node.at } : {},
393
+ ...node.extra ? { extra: node.extra } : {},
394
+ ...pluginElementBadge(node.extra) ? { badge: pluginElementBadge(node.extra) } : {},
395
+ ...node.element ? { element: node.element } : {}
396
+ };
397
+ };
398
+ const mount = dom.findIndex((node) => node.container);
399
+ if (mount !== -1) {
400
+ const node = dom[mount];
401
+ row2.children = row2.children.map(expand);
402
+ return {
403
+ key: `${row2.id}:${mount}`,
404
+ label: node.label,
405
+ kind: "element",
406
+ children: [row2],
407
+ owner: row2.id,
408
+ ...node.at ? { at: node.at } : {},
409
+ ...node.element ? { element: node.element } : {}
410
+ };
411
+ }
412
+ const rendered = dom.map((node, i) => walk(node, `${row2.id}:${i}`)).filter((node) => node !== void 0);
413
+ const rest = row2.children.filter((child) => !placed.has(child)).map(expand);
414
+ const lifted = [];
415
+ const spare = [];
416
+ const adopt = /* @__PURE__ */ new Map();
417
+ for (const child of rest) {
418
+ const reader = child.value && child.id !== void 0 ? readerOf(child.id, row2) : void 0;
419
+ if (reader) {
420
+ const held = adopt.get(reader);
421
+ if (held) held.push(child);
422
+ else adopt.set(reader, [child]);
423
+ placed.add(child);
424
+ continue;
425
+ }
426
+ (child.value || child.prop || child.props ? lifted : spare).push(child);
427
+ }
428
+ for (const [reader, values2] of adopt) reader.children.unshift(...values2);
429
+ row2.children = [...lifted, ...rendered, ...spare];
430
+ return row2;
431
+ };
432
+ const top = roots.map((root) => placed.has(root) ? root : expand(root));
433
+ return top.filter((_, i) => !placed.has(roots[i]));
434
+ }
435
+ const api = {
436
+ render(graph, selected = null) {
437
+ last = { graph, selected };
438
+ const roots = rowsFor(componentTree(graph, { values, filter }), graph);
439
+ const next = `${values}|${filter}|${[...shut].sort().join(",")}|${roots.map(function label(n) {
440
+ return `${n.key}:${n.label}:${n.children.map(label).join("+")}`;
441
+ }).join(",")}`;
442
+ if (next !== signature) {
443
+ signature = next;
444
+ shown = /* @__PURE__ */ new Map();
445
+ const index = (list2) => {
446
+ for (const node of list2) {
447
+ shown.set(node.key, node);
448
+ index(node.children);
449
+ }
450
+ };
451
+ index(roots);
452
+ list.innerHTML = roots.length ? roots.map((node) => row(node, 0)).join("") : `<span class="fx-tree-empty">${escape(filter ? `nothing named ${filter}` : empty)}</span>`;
453
+ }
454
+ if (selected !== marked) {
455
+ marked = selected;
456
+ paint();
457
+ }
458
+ },
459
+ clear() {
460
+ signature = "";
461
+ marked = null;
462
+ shut.clear();
463
+ list.innerHTML = `<span class="fx-tree-empty">${escape(empty)}</span>`;
464
+ },
465
+ destroy() {
466
+ host.removeEventListener("click", onClick);
467
+ host.removeEventListener("dblclick", onDouble);
468
+ host.removeEventListener("pointermove", onOver);
469
+ host.removeEventListener("pointerleave", onOut);
470
+ host.innerHTML = "";
471
+ }
472
+ };
473
+ return api;
474
+ }
475
+ var TREE_CSS = `
476
+ .fx-tree-row {
477
+ display: flex; align-items: center; gap: 4px;
478
+ padding: 1px 6px 1px calc(6px + var(--depth, 0) * 12px);
479
+ font-family: ui-monospace, monospace; font-size: 11.5px;
480
+ color: var(--fx-label, #e7e9ee); cursor: pointer; white-space: nowrap;
481
+ }
482
+ .fx-tree-row:hover { background: var(--fx-hover, #1b1e26); }
483
+ .fx-tree-row.on { background: var(--fx-sel, #232838); }
484
+ .fx-tree-twist {
485
+ width: 12px; padding: 0; border: 0; background: none; cursor: pointer;
486
+ color: var(--fx-muted, #8a90a2); font-size: 9px; line-height: 1;
487
+ }
488
+ .fx-tree-plugin {
489
+ font-size: 9px; color: var(--fx-accent, #5eead4);
490
+ border: 1px solid var(--fx-line, #262a35); border-radius: 6px; padding: 0 4px;
491
+ max-width: 110px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
492
+ }
493
+ .fx-tree-lazy {
494
+ font-size: 9px; letter-spacing: .04em; color: var(--fx-router, #7dd3fc);
495
+ border: 1px solid var(--fx-line, #262a35); border-radius: 6px; padding: 0 4px;
496
+ }
497
+ .fx-tree-count {
498
+ font-size: 9.5px; color: var(--fx-muted, #8a90a2);
499
+ border: 1px solid var(--fx-line, #262a35); border-radius: 6px; padding: 0 4px;
500
+ }
501
+ ${kindRules((k) => `.fx-tree-row.n-${k} .fx-tree-tag`, "color")}
502
+ .fx-tree-bar {
503
+ display: flex; align-items: center; gap: 5px; padding: 2px 8px 5px;
504
+ font-size: 10.5px; color: var(--fx-muted, #8a90a2); cursor: pointer; user-select: none;
505
+ }
506
+ .fx-tree-bar:hover { color: var(--fx-label, #e7e9ee); }
507
+ .fx-tree-bar input { width: 11px; height: 11px; margin: 0; accent-color: var(--fx-accent, #5eead4); }
508
+ .fx-tree-row.n-element:hover .fx-tree-tag { color: var(--fx-label, #e7e9ee); }
509
+ /* A declared value is listed inside the tag that made it, so it reads quieter than a tag. */
510
+ .fx-tree-row.is-value .fx-tree-tag { font-style: italic; opacity: .85; }
511
+ .fx-tree-search {
512
+ width: calc(100% - 16px); margin: 0 8px 4px; padding: 2px 6px;
513
+ font: inherit; font-size: 10.5px;
514
+ color: var(--fx-label, #e7e9ee); background: var(--fx-bg, #0f1115);
515
+ border: 1px solid var(--fx-line, #262a35); border-radius: 4px;
516
+ }
517
+ .fx-tree-search:focus { outline: none; border-color: var(--fx-accent, #5eead4); }
518
+ .fx-tree-empty { display: block; padding: 8px; font-size: 11px; color: var(--fx-muted, #8a90a2); }
519
+ /* A prop reads as what was written on the tag, so it is quieter than the tag itself. */
520
+ /* The row that folds a tag's props away. Dashed, because it stands for something written
521
+ rather than something rendered. */
522
+ .fx-tree-row.is-props .fx-tree-tag {
523
+ display: inline-flex; align-items: center; gap: 5px;
524
+ padding: 0 5px; border: 1px dashed var(--fx-line, #262a35); border-radius: 3px;
525
+ color: var(--fx-muted, #8a90a2); font-size: 10px; letter-spacing: .04em; text-transform: uppercase;
526
+ }
527
+ .fx-tree-row.is-props:hover .fx-tree-tag { border-color: var(--fx-accent, #5eead4); color: var(--fx-label, #e7e9ee); }
528
+ .fx-tree-props-count { opacity: .7; }
529
+
530
+ /* A prop is what was written on the tag above it, so it reads as an aside: the name in a
531
+ quiet chip, the value beside it, and no marker pretending it opens. */
532
+ .fx-tree-row.is-prop .fx-tree-tag { display: inline-flex; align-items: baseline; gap: 5px; min-width: 0; }
533
+ .fx-tree-prop-name {
534
+ flex: none; padding: 0 4px; border-radius: 3px;
535
+ background: var(--fx-chip, rgba(138, 144, 162, .14));
536
+ color: var(--fx-muted, #8a90a2); font-size: 10px; letter-spacing: .02em;
537
+ }
538
+ .fx-tree-row.is-prop:hover .fx-tree-prop-name { color: var(--fx-label, #e7e9ee); }
539
+ .fx-tree-prop-value {
540
+ min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
541
+ color: var(--fx-label, #e7e9ee); opacity: .75;
542
+ }
543
+ `;
544
+ export {
545
+ TREE_CSS,
546
+ TREE_KINDS,
547
+ componentTree,
548
+ createComponentTree,
549
+ idsIn,
550
+ inPageOrder
551
+ };