@fluixi/devtools 0.2.0-alpha.2 → 0.2.0-alpha.4

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 (158) hide show
  1. package/README.md +80 -2
  2. package/dist/callsite.cjs +72 -0
  3. package/dist/callsite.d.ts +22 -0
  4. package/dist/callsite.d.ts.map +1 -0
  5. package/dist/callsite.js +82 -0
  6. package/dist/callsite.mjs +51 -0
  7. package/dist/change-view.cjs +134 -0
  8. package/dist/change-view.d.ts +10 -0
  9. package/dist/change-view.d.ts.map +1 -0
  10. package/dist/change-view.js +102 -0
  11. package/dist/change-view.mjs +111 -0
  12. package/dist/copy.cjs +63 -0
  13. package/dist/copy.d.ts +9 -0
  14. package/dist/copy.d.ts.map +1 -0
  15. package/dist/copy.js +52 -0
  16. package/dist/copy.mjs +42 -0
  17. package/dist/describe.cjs +55 -0
  18. package/dist/describe.d.ts +3 -0
  19. package/dist/describe.d.ts.map +1 -0
  20. package/dist/describe.js +47 -0
  21. package/dist/describe.mjs +34 -0
  22. package/dist/detail-panel.cjs +307 -0
  23. package/dist/detail-panel.d.ts +17 -0
  24. package/dist/detail-panel.d.ts.map +1 -0
  25. package/dist/detail-panel.js +217 -0
  26. package/dist/detail-panel.mjs +284 -0
  27. package/dist/diff.cjs +225 -0
  28. package/dist/diff.d.ts +31 -0
  29. package/dist/diff.d.ts.map +1 -0
  30. package/dist/diff.js +132 -0
  31. package/dist/diff.mjs +202 -0
  32. package/dist/dom.cjs +204 -0
  33. package/dist/dom.d.ts +81 -0
  34. package/dist/dom.d.ts.map +1 -0
  35. package/dist/dom.js +269 -0
  36. package/dist/dom.mjs +183 -0
  37. package/dist/export.cjs +221 -0
  38. package/dist/export.d.ts +55 -0
  39. package/dist/export.d.ts.map +1 -0
  40. package/dist/export.js +90 -0
  41. package/dist/export.mjs +209 -0
  42. package/dist/float.cjs +232 -0
  43. package/dist/float.d.ts +54 -0
  44. package/dist/float.d.ts.map +1 -0
  45. package/dist/float.js +256 -0
  46. package/dist/float.mjs +211 -0
  47. package/dist/format.cjs +175 -0
  48. package/dist/format.d.ts +16 -0
  49. package/dist/format.d.ts.map +1 -0
  50. package/dist/format.js +188 -0
  51. package/dist/format.mjs +154 -0
  52. package/dist/graph-view.cjs +893 -0
  53. package/dist/graph-view.d.ts +79 -2
  54. package/dist/graph-view.d.ts.map +1 -1
  55. package/dist/graph-view.js +866 -50
  56. package/dist/graph-view.mjs +870 -0
  57. package/dist/highlight.cjs +140 -0
  58. package/dist/highlight.d.ts +56 -0
  59. package/dist/highlight.d.ts.map +1 -0
  60. package/dist/highlight.js +154 -0
  61. package/dist/highlight.mjs +119 -0
  62. package/dist/history.cjs +95 -0
  63. package/dist/history.d.ts +59 -0
  64. package/dist/history.d.ts.map +1 -0
  65. package/dist/history.js +85 -0
  66. package/dist/history.mjs +74 -0
  67. package/dist/hook.cjs +1562 -0
  68. package/dist/hook.d.ts +60 -0
  69. package/dist/hook.d.ts.map +1 -0
  70. package/dist/hook.js +142 -0
  71. package/dist/hook.mjs +1553 -0
  72. package/dist/index.cjs +4552 -0
  73. package/dist/index.d.ts +44 -1
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +25 -1
  76. package/dist/index.mjs +4544 -0
  77. package/dist/inspector.cjs +688 -0
  78. package/dist/inspector.d.ts +60 -0
  79. package/dist/inspector.d.ts.map +1 -0
  80. package/dist/inspector.js +415 -0
  81. package/dist/inspector.mjs +676 -0
  82. package/dist/instrument.cjs +497 -0
  83. package/dist/instrument.d.ts +147 -5
  84. package/dist/instrument.d.ts.map +1 -1
  85. package/dist/instrument.js +164 -44
  86. package/dist/instrument.mjs +487 -0
  87. package/dist/kind-filter.cjs +172 -0
  88. package/dist/kind-filter.d.ts +39 -0
  89. package/dist/kind-filter.d.ts.map +1 -0
  90. package/dist/kind-filter.js +151 -0
  91. package/dist/kind-filter.mjs +151 -0
  92. package/dist/menu.cjs +141 -0
  93. package/dist/menu.d.ts +37 -0
  94. package/dist/menu.d.ts.map +1 -0
  95. package/dist/menu.js +125 -0
  96. package/dist/menu.mjs +120 -0
  97. package/dist/observe.cjs +1352 -0
  98. package/dist/observe.d.ts +80 -0
  99. package/dist/observe.d.ts.map +1 -0
  100. package/dist/observe.js +893 -0
  101. package/dist/observe.mjs +1345 -0
  102. package/dist/palette.cjs +52 -0
  103. package/dist/palette.d.ts +11 -0
  104. package/dist/palette.d.ts.map +1 -0
  105. package/dist/palette.js +27 -0
  106. package/dist/palette.mjs +31 -0
  107. package/dist/path.cjs +45 -0
  108. package/dist/path.d.ts +19 -0
  109. package/dist/path.d.ts.map +1 -0
  110. package/dist/path.js +49 -0
  111. package/dist/path.mjs +24 -0
  112. package/dist/plugin.cjs +87 -0
  113. package/dist/plugin.d.ts +121 -0
  114. package/dist/plugin.d.ts.map +1 -0
  115. package/dist/plugin.js +74 -0
  116. package/dist/plugin.mjs +66 -0
  117. package/dist/plugins/context.cjs +98 -0
  118. package/dist/plugins/context.d.ts +10 -0
  119. package/dist/plugins/context.d.ts.map +1 -0
  120. package/dist/plugins/context.js +80 -0
  121. package/dist/plugins/context.mjs +75 -0
  122. package/dist/plugins/directives.cjs +98 -0
  123. package/dist/plugins/directives.d.ts +25 -0
  124. package/dist/plugins/directives.d.ts.map +1 -0
  125. package/dist/plugins/directives.js +78 -0
  126. package/dist/plugins/directives.mjs +75 -0
  127. package/dist/plugins/index.cjs +162 -0
  128. package/dist/plugins/index.d.ts +7 -0
  129. package/dist/plugins/index.d.ts.map +1 -0
  130. package/dist/plugins/index.js +9 -0
  131. package/dist/plugins/index.mjs +140 -0
  132. package/dist/source.cjs +111 -0
  133. package/dist/source.d.ts +72 -0
  134. package/dist/source.d.ts.map +1 -0
  135. package/dist/source.js +153 -0
  136. package/dist/source.mjs +90 -0
  137. package/dist/timeline.cjs +350 -0
  138. package/dist/timeline.d.ts +30 -0
  139. package/dist/timeline.d.ts.map +1 -0
  140. package/dist/timeline.js +271 -0
  141. package/dist/timeline.mjs +327 -0
  142. package/dist/tree.cjs +574 -0
  143. package/dist/tree.d.ts +128 -0
  144. package/dist/tree.d.ts.map +1 -0
  145. package/dist/tree.js +645 -0
  146. package/dist/tree.mjs +551 -0
  147. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  148. package/dist/value-pane.cjs +223 -0
  149. package/dist/value-pane.d.ts +10 -0
  150. package/dist/value-pane.d.ts.map +1 -0
  151. package/dist/value-pane.js +61 -0
  152. package/dist/value-pane.mjs +200 -0
  153. package/dist/wire.cjs +109 -0
  154. package/dist/wire.d.ts +100 -0
  155. package/dist/wire.d.ts.map +1 -0
  156. package/dist/wire.js +93 -0
  157. package/dist/wire.mjs +89 -0
  158. package/package.json +17 -5
@@ -0,0 +1,55 @@
1
+ /**
2
+ * The graph as something to paste somewhere else.
3
+ *
4
+ * A panel shows one node at a time; a bug report needs all of them at once. This is the whole
5
+ * graph as plain json — values, kinds, ownership, sources, what each node reaches in the
6
+ * document and where it is written from.
7
+ *
8
+ * Names rather than ids wherever a reader has to follow a reference: `deps: ["count"]` can be
9
+ * read, `deps: [3]` has to be looked up. Ids stay on the nodes, and a name shared by two nodes
10
+ * is disambiguated so the export is never ambiguous.
11
+ */
12
+ import { type RNode } from './instrument.js';
13
+ import type { GraphEvent } from './history.js';
14
+ export interface ExportOptions {
15
+ /** How much of each value to include. */
16
+ limit?: number;
17
+ /** The history, when the host has one. */
18
+ events?: readonly GraphEvent[];
19
+ /** Says the graph was read from source rather than from a running application. */
20
+ fromSource?: boolean;
21
+ }
22
+ interface ExportedNode {
23
+ id: number;
24
+ label: string;
25
+ kind: string;
26
+ /** Absent when the framework named it — see RNode.authored. */
27
+ authored?: boolean;
28
+ value?: string;
29
+ runs?: number;
30
+ version?: number;
31
+ state?: string;
32
+ reads?: string[];
33
+ writes?: string[];
34
+ madeIn?: string;
35
+ source?: string;
36
+ declaredAt?: string;
37
+ usedAt?: string;
38
+ /** Where it reaches the document, with the line each binding was written on. */
39
+ updates?: string[];
40
+ /** Where it is written from, outside any computation. */
41
+ setAt?: string[];
42
+ }
43
+ export interface ExportedGraph {
44
+ t: number;
45
+ nodes: ExportedNode[];
46
+ /** Present only when the host passed a history. */
47
+ events?: GraphEvent[];
48
+ from: 'source' | 'running application';
49
+ }
50
+ /** The graph as a plain object. */
51
+ export declare function exportGraph(graph: Map<number, RNode>, options?: ExportOptions): ExportedGraph;
52
+ /** The same thing as text, indented so it can be read where it is pasted. */
53
+ export declare function graphToJson(graph: Map<number, RNode>, options?: ExportOptions): string;
54
+ export {};
55
+ //# sourceMappingURL=export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../src/export.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAA0B,KAAK,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAErE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/C,MAAM,WAAW,aAAa;IAC5B,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,MAAM,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC/B,kFAAkF;IAClF,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAsBD,MAAM,WAAW,aAAa;IAC5B,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,mDAAmD;IACnD,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;IACtB,IAAI,EAAE,QAAQ,GAAG,qBAAqB,CAAC;CACxC;AAED,mCAAmC;AACnC,wBAAgB,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAE,aAAkB,GAAG,aAAa,CAoDjG;AAED,6EAA6E;AAC7E,wBAAgB,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAE1F"}
package/dist/export.js ADDED
@@ -0,0 +1,90 @@
1
+ /**
2
+ * The graph as something to paste somewhere else.
3
+ *
4
+ * A panel shows one node at a time; a bug report needs all of them at once. This is the whole
5
+ * graph as plain json — values, kinds, ownership, sources, what each node reaches in the
6
+ * document and where it is written from.
7
+ *
8
+ * Names rather than ids wherever a reader has to follow a reference: `deps: ["count"]` can be
9
+ * read, `deps: [3]` has to be looked up. Ids stay on the nodes, and a name shared by two nodes
10
+ * is disambiguated so the export is never ambiguous.
11
+ */
12
+ import { nodeState, nodeVersion } from './instrument.js';
13
+ import { formatValue } from './format.js';
14
+ const at = (source) => {
15
+ if (!source)
16
+ return undefined;
17
+ const where = `${source.file ?? ''}:${source.line ?? ''}:${source.column ?? ''}`;
18
+ // Both when they differ: a template's holes share one original position.
19
+ const out = source.compiled;
20
+ const same = out?.line === source.line && out?.column === source.column;
21
+ return out && !same ? `${where} (out ${out.line ?? ''}:${out.column ?? ''})` : where;
22
+ };
23
+ /** A name, made unique when two nodes share it. */
24
+ function naming(graph) {
25
+ const seen = new Map();
26
+ for (const node of graph.values())
27
+ seen.set(node.label, (seen.get(node.label) ?? 0) + 1);
28
+ return (id) => {
29
+ const node = graph.get(id);
30
+ if (!node)
31
+ return `#${id}`;
32
+ return (seen.get(node.label) ?? 0) > 1 ? `${node.label}#${node.id}` : node.label;
33
+ };
34
+ }
35
+ /** The graph as a plain object. */
36
+ export function exportGraph(graph, options = {}) {
37
+ const limit = options.limit ?? 400;
38
+ const name = naming(graph);
39
+ const nodes = [...graph.values()].map((node) => {
40
+ let value = node.detail ?? node.value;
41
+ if (node.read) {
42
+ try {
43
+ value = formatValue(node.read(), limit);
44
+ }
45
+ catch {
46
+ // A reader that throws is still a node worth exporting.
47
+ }
48
+ }
49
+ const feeds = [...node.deps].map(name);
50
+ const wrote = [...node.writes].map(name);
51
+ const state = nodeState(node);
52
+ return {
53
+ id: node.id,
54
+ label: node.label,
55
+ kind: node.kind,
56
+ ...(node.authored === false ? { authored: false } : {}),
57
+ ...(value ? { value } : {}),
58
+ ...(node.runs ? { runs: node.runs } : {}),
59
+ // Only a node with a core has one; a static node would report a version of 0.
60
+ ...(node.core?.version !== undefined ? { version: nodeVersion(node) } : {}),
61
+ ...(state ? { state } : {}),
62
+ ...(feeds.length ? { reads: feeds } : {}),
63
+ ...(wrote.length ? { writes: wrote } : {}),
64
+ ...(node.createdIn !== undefined ? { madeIn: name(node.createdIn) } : {}),
65
+ ...(at(node.source) ? { source: at(node.source) } : {}),
66
+ ...(at(node.declaredAt) ? { declaredAt: at(node.declaredAt) } : {}),
67
+ ...(at(node.usedAt) ? { usedAt: at(node.usedAt) } : {}),
68
+ ...(node.targets?.length
69
+ ? {
70
+ updates: node.targets.map((target) => {
71
+ const what = target.name ? `${target.name} of ${target.element}` : target.element;
72
+ const where = at(target.source);
73
+ return where ? `${what} — ${where}` : what;
74
+ }),
75
+ }
76
+ : {}),
77
+ ...(node.setAt?.length ? { setAt: node.setAt.map((s) => at(s)).filter(Boolean) } : {}),
78
+ };
79
+ });
80
+ return {
81
+ t: Date.now(),
82
+ from: options.fromSource ? 'source' : 'running application',
83
+ nodes,
84
+ ...(options.events?.length ? { events: [...options.events] } : {}),
85
+ };
86
+ }
87
+ /** The same thing as text, indented so it can be read where it is pasted. */
88
+ export function graphToJson(graph, options = {}) {
89
+ return JSON.stringify(exportGraph(graph, options), null, 2);
90
+ }
@@ -0,0 +1,209 @@
1
+ // src/instrument.ts
2
+ import {
3
+ createSignal,
4
+ createMemo,
5
+ createEffect,
6
+ createResource,
7
+ createRoot,
8
+ untrack,
9
+ onCleanup,
10
+ getOwner,
11
+ runWithOwner,
12
+ Signal
13
+ } from "@fluixi/reactive/signal";
14
+ import { createStore } from "@fluixi/reactive/store";
15
+
16
+ // src/source.ts
17
+ var MARKS = "__FLUIXI_DEVTOOLS_MARKS__";
18
+ var host = globalThis;
19
+ var shared = host[MARKS] ?? {
20
+ pending: null,
21
+ expiring: false,
22
+ components: /* @__PURE__ */ new Map()
23
+ };
24
+ host[MARKS] = shared;
25
+
26
+ // src/format.ts
27
+ var MAX_DEPTH = 3;
28
+ var MAX_ENTRIES = 8;
29
+ function domName(v) {
30
+ if (typeof v?.nodeType !== "number" || typeof v.nodeName !== "string") return null;
31
+ return v.tagName ? `<${v.tagName.toLowerCase()}>` : `#${v.nodeName.toLowerCase()}`;
32
+ }
33
+ function fnName(v) {
34
+ return v.name ? `ƒ ${v.name}()` : "ƒ";
35
+ }
36
+ function className(v) {
37
+ const name = v.constructor?.name;
38
+ return name && name !== "Object" ? `${name} ` : "";
39
+ }
40
+ function primitive(v) {
41
+ if (v === null) return "null";
42
+ switch (typeof v) {
43
+ case "undefined":
44
+ return "undefined";
45
+ case "string":
46
+ return JSON.stringify(v);
47
+ case "number":
48
+ case "boolean":
49
+ return String(v);
50
+ case "bigint":
51
+ return `${v}n`;
52
+ case "symbol":
53
+ return v.toString();
54
+ case "function":
55
+ return fnName(v);
56
+ default:
57
+ return null;
58
+ }
59
+ }
60
+ function walk(value, depth, seen) {
61
+ const simple = primitive(value);
62
+ if (simple !== null) return simple;
63
+ const object = value;
64
+ if (seen.has(object)) return "[circular]";
65
+ const dom = domName(object);
66
+ if (dom) return dom;
67
+ if (object instanceof Date) return Number.isNaN(object.getTime()) ? "Invalid Date" : object.toISOString();
68
+ if (object instanceof RegExp) return String(object);
69
+ if (object instanceof Error) return `${object.name}: ${object.message}`;
70
+ if (object instanceof Promise) return "Promise";
71
+ if (ArrayBuffer.isView(object)) {
72
+ return `${className(object).trim()}(${object.length ?? ""})`;
73
+ }
74
+ if (depth >= MAX_DEPTH) return Array.isArray(object) ? "[…]" : "{…}";
75
+ seen.add(object);
76
+ try {
77
+ if (Array.isArray(object)) {
78
+ const shown2 = object.slice(0, MAX_ENTRIES).map((item) => walk(item, depth + 1, seen));
79
+ if (object.length > MAX_ENTRIES) shown2.push("…");
80
+ return `[${shown2.join(", ")}]`;
81
+ }
82
+ if (object instanceof Map) {
83
+ const shown2 = [];
84
+ for (const [k, v] of object) {
85
+ if (shown2.length === MAX_ENTRIES) {
86
+ shown2.push("…");
87
+ break;
88
+ }
89
+ shown2.push(`${walk(k, depth + 1, seen)} => ${walk(v, depth + 1, seen)}`);
90
+ }
91
+ return `Map(${object.size}) {${shown2.join(", ")}}`;
92
+ }
93
+ if (object instanceof Set) {
94
+ const shown2 = [];
95
+ for (const item of object) {
96
+ if (shown2.length === MAX_ENTRIES) {
97
+ shown2.push("…");
98
+ break;
99
+ }
100
+ shown2.push(walk(item, depth + 1, seen));
101
+ }
102
+ return `Set(${object.size}) {${shown2.join(", ")}}`;
103
+ }
104
+ const keys = Object.keys(object);
105
+ const shown = keys.slice(0, MAX_ENTRIES).map((key) => {
106
+ let read;
107
+ try {
108
+ read = walk(object[key], depth + 1, seen);
109
+ } catch {
110
+ read = "[unreadable]";
111
+ }
112
+ return `${key}: ${read}`;
113
+ });
114
+ if (keys.length > MAX_ENTRIES) shown.push("…");
115
+ return `${className(object)}{${shown.join(", ")}}`;
116
+ } finally {
117
+ seen.delete(object);
118
+ }
119
+ }
120
+ function formatValue(value, limit = 240) {
121
+ let text;
122
+ try {
123
+ text = walk(value, 0, /* @__PURE__ */ new Set());
124
+ } catch {
125
+ text = "[unreadable]";
126
+ }
127
+ return text.length > limit ? `${text.slice(0, limit - 1)}…` : text;
128
+ }
129
+
130
+ // src/instrument.ts
131
+ var CORE_STATE = { 0: "clean", 1: "check", 2: "dirty" };
132
+ function nodeVersion(n) {
133
+ return n.core && typeof n.core.version === "number" ? n.core.version : n.runs;
134
+ }
135
+ function nodeState(n) {
136
+ return n.core && typeof n.core.state === "number" ? CORE_STATE[n.core.state] : void 0;
137
+ }
138
+
139
+ // src/export.ts
140
+ var at = (source) => {
141
+ if (!source) return void 0;
142
+ const where = `${source.file ?? ""}:${source.line ?? ""}:${source.column ?? ""}`;
143
+ const out = source.compiled;
144
+ const same = out?.line === source.line && out?.column === source.column;
145
+ return out && !same ? `${where} (out ${out.line ?? ""}:${out.column ?? ""})` : where;
146
+ };
147
+ function naming(graph) {
148
+ const seen = /* @__PURE__ */ new Map();
149
+ for (const node of graph.values()) seen.set(node.label, (seen.get(node.label) ?? 0) + 1);
150
+ return (id) => {
151
+ const node = graph.get(id);
152
+ if (!node) return `#${id}`;
153
+ return (seen.get(node.label) ?? 0) > 1 ? `${node.label}#${node.id}` : node.label;
154
+ };
155
+ }
156
+ function exportGraph(graph, options = {}) {
157
+ const limit = options.limit ?? 400;
158
+ const name = naming(graph);
159
+ const nodes = [...graph.values()].map((node) => {
160
+ let value = node.detail ?? node.value;
161
+ if (node.read) {
162
+ try {
163
+ value = formatValue(node.read(), limit);
164
+ } catch {
165
+ }
166
+ }
167
+ const feeds = [...node.deps].map(name);
168
+ const wrote = [...node.writes].map(name);
169
+ const state = nodeState(node);
170
+ return {
171
+ id: node.id,
172
+ label: node.label,
173
+ kind: node.kind,
174
+ ...node.authored === false ? { authored: false } : {},
175
+ ...value ? { value } : {},
176
+ ...node.runs ? { runs: node.runs } : {},
177
+ // Only a node with a core has one; a static node would report a version of 0.
178
+ ...node.core?.version !== void 0 ? { version: nodeVersion(node) } : {},
179
+ ...state ? { state } : {},
180
+ ...feeds.length ? { reads: feeds } : {},
181
+ ...wrote.length ? { writes: wrote } : {},
182
+ ...node.createdIn !== void 0 ? { madeIn: name(node.createdIn) } : {},
183
+ ...at(node.source) ? { source: at(node.source) } : {},
184
+ ...at(node.declaredAt) ? { declaredAt: at(node.declaredAt) } : {},
185
+ ...at(node.usedAt) ? { usedAt: at(node.usedAt) } : {},
186
+ ...node.targets?.length ? {
187
+ updates: node.targets.map((target) => {
188
+ const what = target.name ? `${target.name} of ${target.element}` : target.element;
189
+ const where = at(target.source);
190
+ return where ? `${what} — ${where}` : what;
191
+ })
192
+ } : {},
193
+ ...node.setAt?.length ? { setAt: node.setAt.map((s) => at(s)).filter(Boolean) } : {}
194
+ };
195
+ });
196
+ return {
197
+ t: Date.now(),
198
+ from: options.fromSource ? "source" : "running application",
199
+ nodes,
200
+ ...options.events?.length ? { events: [...options.events] } : {}
201
+ };
202
+ }
203
+ function graphToJson(graph, options = {}) {
204
+ return JSON.stringify(exportGraph(graph, options), null, 2);
205
+ }
206
+ export {
207
+ exportGraph,
208
+ graphToJson
209
+ };
package/dist/float.cjs ADDED
@@ -0,0 +1,232 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/float.ts
21
+ var float_exports = {};
22
+ __export(float_exports, {
23
+ FLOAT_CSS: () => FLOAT_CSS,
24
+ floatCard: () => floatCard,
25
+ makeFloatable: () => makeFloatable
26
+ });
27
+ module.exports = __toCommonJS(float_exports);
28
+ var MIN_W = 240;
29
+ var MIN_H = 160;
30
+ function draggable(handle, onMove, onStart) {
31
+ handle.addEventListener("pointerdown", (event) => {
32
+ if (event.button !== 0) return;
33
+ if (event.target.closest("button")) return;
34
+ event.preventDefault();
35
+ handle.setPointerCapture(event.pointerId);
36
+ const fromX = event.clientX;
37
+ const fromY = event.clientY;
38
+ onStart?.();
39
+ const move = (e) => onMove(e.clientX - fromX, e.clientY - fromY);
40
+ const stop = () => {
41
+ handle.removeEventListener("pointermove", move);
42
+ handle.removeEventListener("pointerup", stop);
43
+ handle.removeEventListener("pointercancel", stop);
44
+ handle.removeEventListener("lostpointercapture", stop);
45
+ if (handle.hasPointerCapture(event.pointerId)) handle.releasePointerCapture(event.pointerId);
46
+ };
47
+ handle.addEventListener("pointermove", move);
48
+ handle.addEventListener("pointerup", stop);
49
+ handle.addEventListener("pointercancel", stop);
50
+ handle.addEventListener("lostpointercapture", stop);
51
+ });
52
+ }
53
+ var opened = 0;
54
+ function floatCard(doc, title, at) {
55
+ const card = doc.createElement("div");
56
+ card.className = "fx-float";
57
+ const spot = at ?? {
58
+ x: 60 + opened % 4 * 28,
59
+ y: 60 + opened % 4 * 28,
60
+ width: 360,
61
+ height: 280
62
+ };
63
+ opened += 1;
64
+ const bar = doc.createElement("div");
65
+ bar.className = "fx-float-bar";
66
+ const name = doc.createElement("span");
67
+ name.textContent = title;
68
+ bar.append(name);
69
+ card.append(bar);
70
+ let x = spot.x;
71
+ let y = spot.y;
72
+ let w = spot.width;
73
+ let h = spot.height;
74
+ const apply = () => {
75
+ const view = doc.defaultView;
76
+ const vw = view?.innerWidth ?? w;
77
+ const vh = view?.innerHeight ?? h;
78
+ w = Math.min(Math.max(MIN_W, w), vw);
79
+ h = Math.min(Math.max(MIN_H, h), vh);
80
+ x = Math.min(Math.max(0, x), Math.max(0, vw - w));
81
+ y = Math.min(Math.max(0, y), Math.max(0, vh - h));
82
+ card.style.left = `${x}px`;
83
+ card.style.top = `${y}px`;
84
+ card.style.width = `${w}px`;
85
+ card.style.height = `${h}px`;
86
+ };
87
+ let from = { x, y, w, h };
88
+ const remember = () => {
89
+ from = { x, y, w, h };
90
+ };
91
+ for (const edge of ["n", "s", "e", "w", "ne", "nw", "se", "sw"]) {
92
+ const handle = doc.createElement("div");
93
+ handle.className = `fx-float-h fx-float-${edge}`;
94
+ card.append(handle);
95
+ draggable(
96
+ handle,
97
+ (dx, dy) => {
98
+ if (edge.includes("e")) w = from.w + dx;
99
+ if (edge.includes("s")) h = from.h + dy;
100
+ if (edge.includes("w")) {
101
+ w = Math.max(MIN_W, from.w - dx);
102
+ x = from.x + from.w - w;
103
+ }
104
+ if (edge.includes("n")) {
105
+ h = Math.max(MIN_H, from.h - dy);
106
+ y = from.y + from.h - h;
107
+ }
108
+ apply();
109
+ },
110
+ remember
111
+ );
112
+ }
113
+ draggable(
114
+ bar,
115
+ (dx, dy) => {
116
+ x = from.x + dx;
117
+ y = from.y + dy;
118
+ apply();
119
+ },
120
+ remember
121
+ );
122
+ apply();
123
+ return { card, bar, remove: () => card.remove() };
124
+ }
125
+ function makeFloatable(pane, options) {
126
+ const doc = pane.ownerDocument;
127
+ let card = null;
128
+ let home = null;
129
+ const button = doc.createElement("button");
130
+ button.type = "button";
131
+ button.className = "fx-float-btn";
132
+ button.textContent = "⇱";
133
+ button.title = `Float ${options.title}`;
134
+ pane.classList.add("fx-floatable");
135
+ pane.append(button);
136
+ const keep = new MutationObserver(() => {
137
+ if (button.parentNode !== pane) pane.append(button);
138
+ });
139
+ keep.observe(pane, { childList: true });
140
+ function dock() {
141
+ if (!card || !home) return;
142
+ home.parent.insertBefore(pane, home.before);
143
+ card.remove();
144
+ card = null;
145
+ home = null;
146
+ pane.classList.remove("fx-floated");
147
+ button.textContent = "⇱";
148
+ button.title = `Float ${options.title}`;
149
+ options.onChange?.(false);
150
+ }
151
+ function float() {
152
+ if (card || !pane.parentNode) return;
153
+ home = { parent: pane.parentNode, before: pane.nextSibling };
154
+ const built = floatCard(doc, options.title, options.at);
155
+ card = built.card;
156
+ card.append(pane);
157
+ doc.body.appendChild(card);
158
+ pane.classList.add("fx-floated");
159
+ button.textContent = "⇲";
160
+ button.title = `Put ${options.title} back`;
161
+ options.onChange?.(true);
162
+ }
163
+ button.addEventListener("click", (event) => {
164
+ event.stopPropagation();
165
+ if (card) dock();
166
+ else float();
167
+ });
168
+ return {
169
+ get floating() {
170
+ return card !== null;
171
+ },
172
+ toggle() {
173
+ if (card) dock();
174
+ else float();
175
+ return card !== null;
176
+ },
177
+ dock,
178
+ destroy() {
179
+ keep.disconnect();
180
+ dock();
181
+ button.remove();
182
+ pane.classList.remove("fx-floatable");
183
+ }
184
+ };
185
+ }
186
+ var FLOAT_CSS = `
187
+ .fx-floatable { position: relative; }
188
+ .fx-float-btn {
189
+ position: absolute; top: 2px; right: 2px; z-index: 5;
190
+ width: 18px; height: 18px; padding: 0; line-height: 1;
191
+ font-size: 11px; color: var(--fx-muted, #8a90a2);
192
+ background: var(--fx-panel, #14161c);
193
+ border: 1px solid var(--fx-line, #262a35); border-radius: 4px;
194
+ cursor: pointer; opacity: 0; transition: opacity .12s;
195
+ }
196
+ .fx-floatable:hover .fx-float-btn, .fx-float-btn:focus-visible { opacity: 1; }
197
+ .fx-float-btn:hover { color: var(--fx-accent, #5eead4); border-color: var(--fx-accent, #5eead4); }
198
+
199
+ .fx-float {
200
+ position: fixed; z-index: 60; display: flex; flex-direction: column;
201
+ background: var(--fx-panel, #14161c);
202
+ border: 1px solid var(--fx-line, #262a35); border-radius: 8px;
203
+ box-shadow: 0 12px 34px rgba(0, 0, 0, .5); overflow: hidden;
204
+ }
205
+ .fx-float-bar {
206
+ display: flex; align-items: center; padding: 4px 8px; cursor: move;
207
+ font-size: 11px; color: var(--fx-muted, #8a90a2);
208
+ background: var(--fx-bg, #0f1115); border-bottom: 1px solid var(--fx-line, #262a35);
209
+ user-select: none;
210
+ }
211
+ /* The pane fills the card, whatever it was sized to in the layout it came from. */
212
+ .fx-float > .fx-floated {
213
+ flex: 1; min-height: 0; width: auto; height: auto; overflow: auto;
214
+ }
215
+ /* Edges and corners. Thin, and over everything, so a card can be resized from whichever
216
+ side is reachable. */
217
+ .fx-float-h { position: absolute; z-index: 1; }
218
+ .fx-float-n, .fx-float-s { left: 8px; right: 8px; height: 6px; cursor: ns-resize; }
219
+ .fx-float-e, .fx-float-w { top: 8px; bottom: 8px; width: 6px; cursor: ew-resize; }
220
+ .fx-float-n { top: -3px; }
221
+ .fx-float-s { bottom: -3px; }
222
+ .fx-float-e { right: -3px; }
223
+ .fx-float-w { left: -3px; }
224
+ .fx-float-ne, .fx-float-nw, .fx-float-se, .fx-float-sw { width: 14px; height: 14px; }
225
+ .fx-float-nw { top: -3px; left: -3px; cursor: nwse-resize; }
226
+ .fx-float-ne { top: -3px; right: -3px; cursor: nesw-resize; }
227
+ .fx-float-sw { bottom: -3px; left: -3px; cursor: nesw-resize; }
228
+ .fx-float-se {
229
+ bottom: 0; right: 0; cursor: nwse-resize;
230
+ background: linear-gradient(135deg, transparent 50%, var(--fx-line, #262a35) 50%);
231
+ }
232
+ `;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Taking a pane out of the layout and putting it back.
3
+ *
4
+ * The inspector, the timeline and the tree each live in a fixed corner of the panel. Reading
5
+ * one of them properly means giving it room, and the room has to come from the others. So
6
+ * each carries a button that lifts it into a card over everything, and the same button puts
7
+ * it back exactly where it was.
8
+ *
9
+ * The pane element itself is moved rather than re-rendered. Whatever drew into it keeps its
10
+ * handle on it, its listeners, and its scroll position — a floated timeline is the same
11
+ * timeline, not a copy of one.
12
+ */
13
+ export interface FloatOptions {
14
+ /** Shown on the card's bar, and on the button that lifts it. */
15
+ title: string;
16
+ /** Where a card opens the first time. Defaults to a cascade from the top left. */
17
+ at?: {
18
+ x: number;
19
+ y: number;
20
+ width: number;
21
+ height: number;
22
+ };
23
+ /** Told each way round, for a host that wants to remember or relayout. */
24
+ onChange?: (floating: boolean) => void;
25
+ }
26
+ export interface Floatable {
27
+ readonly floating: boolean;
28
+ /** Lift it out, or put it back. Returns what it now is. */
29
+ toggle(): boolean;
30
+ dock(): void;
31
+ destroy(): void;
32
+ }
33
+ /** A card the reader can move and resize, with the pane's own content inside it. */
34
+ export interface FloatCard {
35
+ readonly card: HTMLElement;
36
+ /** The bar along the top, for a title or a close button. */
37
+ readonly bar: HTMLElement;
38
+ remove(): void;
39
+ }
40
+ /**
41
+ * The moving and resizing, on its own.
42
+ *
43
+ * Both a floated pane and the value pane want the same card, and writing the drag twice is
44
+ * how two of them end up behaving differently.
45
+ */
46
+ export declare function floatCard(doc: Document, title: string, at?: {
47
+ x: number;
48
+ y: number;
49
+ width: number;
50
+ height: number;
51
+ }): FloatCard;
52
+ export declare function makeFloatable(pane: HTMLElement, options: FloatOptions): Floatable;
53
+ export declare const FLOAT_CSS = "\n.fx-floatable { position: relative; }\n.fx-float-btn {\n position: absolute; top: 2px; right: 2px; z-index: 5;\n width: 18px; height: 18px; padding: 0; line-height: 1;\n font-size: 11px; color: var(--fx-muted, #8a90a2);\n background: var(--fx-panel, #14161c);\n border: 1px solid var(--fx-line, #262a35); border-radius: 4px;\n cursor: pointer; opacity: 0; transition: opacity .12s;\n}\n.fx-floatable:hover .fx-float-btn, .fx-float-btn:focus-visible { opacity: 1; }\n.fx-float-btn:hover { color: var(--fx-accent, #5eead4); border-color: var(--fx-accent, #5eead4); }\n\n.fx-float {\n position: fixed; z-index: 60; display: flex; flex-direction: column;\n background: var(--fx-panel, #14161c);\n border: 1px solid var(--fx-line, #262a35); border-radius: 8px;\n box-shadow: 0 12px 34px rgba(0, 0, 0, .5); overflow: hidden;\n}\n.fx-float-bar {\n display: flex; align-items: center; padding: 4px 8px; cursor: move;\n font-size: 11px; color: var(--fx-muted, #8a90a2);\n background: var(--fx-bg, #0f1115); border-bottom: 1px solid var(--fx-line, #262a35);\n user-select: none;\n}\n/* The pane fills the card, whatever it was sized to in the layout it came from. */\n.fx-float > .fx-floated {\n flex: 1; min-height: 0; width: auto; height: auto; overflow: auto;\n}\n/* Edges and corners. Thin, and over everything, so a card can be resized from whichever\n side is reachable. */\n.fx-float-h { position: absolute; z-index: 1; }\n.fx-float-n, .fx-float-s { left: 8px; right: 8px; height: 6px; cursor: ns-resize; }\n.fx-float-e, .fx-float-w { top: 8px; bottom: 8px; width: 6px; cursor: ew-resize; }\n.fx-float-n { top: -3px; }\n.fx-float-s { bottom: -3px; }\n.fx-float-e { right: -3px; }\n.fx-float-w { left: -3px; }\n.fx-float-ne, .fx-float-nw, .fx-float-se, .fx-float-sw { width: 14px; height: 14px; }\n.fx-float-nw { top: -3px; left: -3px; cursor: nwse-resize; }\n.fx-float-ne { top: -3px; right: -3px; cursor: nesw-resize; }\n.fx-float-sw { bottom: -3px; left: -3px; cursor: nesw-resize; }\n.fx-float-se {\n bottom: 0; right: 0; cursor: nwse-resize;\n background: linear-gradient(135deg, transparent 50%, var(--fx-line, #262a35) 50%);\n}\n";
54
+ //# sourceMappingURL=float.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"float.d.ts","sourceRoot":"","sources":["../src/float.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA+CH,MAAM,WAAW,YAAY;IAC3B,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,kFAAkF;IAClF,EAAE,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,2DAA2D;IAC3D,MAAM,IAAI,OAAO,CAAC;IAClB,IAAI,IAAI,IAAI,CAAC;IACb,OAAO,IAAI,IAAI,CAAC;CACjB;AAMD,oFAAoF;AACpF,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,4DAA4D;IAC5D,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAC1B,MAAM,IAAI,IAAI,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,QAAQ,EACb,KAAK,EAAE,MAAM,EACb,EAAE,CAAC,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC3D,SAAS,CAsFX;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,GAAG,SAAS,CA2EjF;AAED,eAAO,MAAM,SAAS,8mEA8CrB,CAAC"}