@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.
- package/README.md +80 -2
- package/dist/callsite.cjs +72 -0
- package/dist/callsite.d.ts +22 -0
- package/dist/callsite.d.ts.map +1 -0
- package/dist/callsite.js +82 -0
- package/dist/callsite.mjs +51 -0
- package/dist/change-view.cjs +134 -0
- package/dist/change-view.d.ts +10 -0
- package/dist/change-view.d.ts.map +1 -0
- package/dist/change-view.js +102 -0
- package/dist/change-view.mjs +111 -0
- package/dist/copy.cjs +63 -0
- package/dist/copy.d.ts +9 -0
- package/dist/copy.d.ts.map +1 -0
- package/dist/copy.js +52 -0
- package/dist/copy.mjs +42 -0
- package/dist/describe.cjs +55 -0
- package/dist/describe.d.ts +3 -0
- package/dist/describe.d.ts.map +1 -0
- package/dist/describe.js +47 -0
- package/dist/describe.mjs +34 -0
- package/dist/detail-panel.cjs +307 -0
- package/dist/detail-panel.d.ts +17 -0
- package/dist/detail-panel.d.ts.map +1 -0
- package/dist/detail-panel.js +217 -0
- package/dist/detail-panel.mjs +284 -0
- package/dist/diff.cjs +225 -0
- package/dist/diff.d.ts +31 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +132 -0
- package/dist/diff.mjs +202 -0
- package/dist/dom.cjs +204 -0
- package/dist/dom.d.ts +81 -0
- package/dist/dom.d.ts.map +1 -0
- package/dist/dom.js +269 -0
- package/dist/dom.mjs +183 -0
- package/dist/export.cjs +221 -0
- package/dist/export.d.ts +55 -0
- package/dist/export.d.ts.map +1 -0
- package/dist/export.js +90 -0
- package/dist/export.mjs +209 -0
- package/dist/float.cjs +232 -0
- package/dist/float.d.ts +54 -0
- package/dist/float.d.ts.map +1 -0
- package/dist/float.js +256 -0
- package/dist/float.mjs +211 -0
- package/dist/format.cjs +175 -0
- package/dist/format.d.ts +16 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +188 -0
- package/dist/format.mjs +154 -0
- package/dist/graph-view.cjs +893 -0
- package/dist/graph-view.d.ts +79 -2
- package/dist/graph-view.d.ts.map +1 -1
- package/dist/graph-view.js +866 -50
- package/dist/graph-view.mjs +870 -0
- package/dist/highlight.cjs +140 -0
- package/dist/highlight.d.ts +56 -0
- package/dist/highlight.d.ts.map +1 -0
- package/dist/highlight.js +154 -0
- package/dist/highlight.mjs +119 -0
- package/dist/history.cjs +95 -0
- package/dist/history.d.ts +59 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +85 -0
- package/dist/history.mjs +74 -0
- package/dist/hook.cjs +1562 -0
- package/dist/hook.d.ts +60 -0
- package/dist/hook.d.ts.map +1 -0
- package/dist/hook.js +142 -0
- package/dist/hook.mjs +1553 -0
- package/dist/index.cjs +4552 -0
- package/dist/index.d.ts +44 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -1
- package/dist/index.mjs +4544 -0
- package/dist/inspector.cjs +688 -0
- package/dist/inspector.d.ts +60 -0
- package/dist/inspector.d.ts.map +1 -0
- package/dist/inspector.js +415 -0
- package/dist/inspector.mjs +676 -0
- package/dist/instrument.cjs +497 -0
- package/dist/instrument.d.ts +147 -5
- package/dist/instrument.d.ts.map +1 -1
- package/dist/instrument.js +164 -44
- package/dist/instrument.mjs +487 -0
- package/dist/kind-filter.cjs +172 -0
- package/dist/kind-filter.d.ts +39 -0
- package/dist/kind-filter.d.ts.map +1 -0
- package/dist/kind-filter.js +151 -0
- package/dist/kind-filter.mjs +151 -0
- package/dist/menu.cjs +141 -0
- package/dist/menu.d.ts +37 -0
- package/dist/menu.d.ts.map +1 -0
- package/dist/menu.js +125 -0
- package/dist/menu.mjs +120 -0
- package/dist/observe.cjs +1352 -0
- package/dist/observe.d.ts +80 -0
- package/dist/observe.d.ts.map +1 -0
- package/dist/observe.js +893 -0
- package/dist/observe.mjs +1345 -0
- package/dist/palette.cjs +52 -0
- package/dist/palette.d.ts +11 -0
- package/dist/palette.d.ts.map +1 -0
- package/dist/palette.js +27 -0
- package/dist/palette.mjs +31 -0
- package/dist/path.cjs +45 -0
- package/dist/path.d.ts +19 -0
- package/dist/path.d.ts.map +1 -0
- package/dist/path.js +49 -0
- package/dist/path.mjs +24 -0
- package/dist/plugin.cjs +87 -0
- package/dist/plugin.d.ts +121 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +74 -0
- package/dist/plugin.mjs +66 -0
- package/dist/plugins/context.cjs +98 -0
- package/dist/plugins/context.d.ts +10 -0
- package/dist/plugins/context.d.ts.map +1 -0
- package/dist/plugins/context.js +80 -0
- package/dist/plugins/context.mjs +75 -0
- package/dist/plugins/directives.cjs +98 -0
- package/dist/plugins/directives.d.ts +25 -0
- package/dist/plugins/directives.d.ts.map +1 -0
- package/dist/plugins/directives.js +78 -0
- package/dist/plugins/directives.mjs +75 -0
- package/dist/plugins/index.cjs +162 -0
- package/dist/plugins/index.d.ts +7 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +9 -0
- package/dist/plugins/index.mjs +140 -0
- package/dist/source.cjs +111 -0
- package/dist/source.d.ts +72 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +153 -0
- package/dist/source.mjs +90 -0
- package/dist/timeline.cjs +350 -0
- package/dist/timeline.d.ts +30 -0
- package/dist/timeline.d.ts.map +1 -0
- package/dist/timeline.js +271 -0
- package/dist/timeline.mjs +327 -0
- package/dist/tree.cjs +574 -0
- package/dist/tree.d.ts +128 -0
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +645 -0
- package/dist/tree.mjs +551 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/value-pane.cjs +223 -0
- package/dist/value-pane.d.ts +10 -0
- package/dist/value-pane.d.ts.map +1 -0
- package/dist/value-pane.js +61 -0
- package/dist/value-pane.mjs +200 -0
- package/dist/wire.cjs +109 -0
- package/dist/wire.d.ts +100 -0
- package/dist/wire.d.ts.map +1 -0
- package/dist/wire.js +93 -0
- package/dist/wire.mjs +89 -0
- package/package.json +17 -5
|
@@ -0,0 +1,140 @@
|
|
|
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/highlight.ts
|
|
21
|
+
var highlight_exports = {};
|
|
22
|
+
__export(highlight_exports, {
|
|
23
|
+
hideHighlight: () => hideHighlight,
|
|
24
|
+
removeHighlight: () => removeHighlight,
|
|
25
|
+
showHighlight: () => showHighlight,
|
|
26
|
+
startPicking: () => startPicking
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(highlight_exports);
|
|
29
|
+
var LAYER = "fx-highlight-layer";
|
|
30
|
+
var overlay = null;
|
|
31
|
+
function build(doc) {
|
|
32
|
+
const layer = doc.createElement("div");
|
|
33
|
+
layer.id = LAYER;
|
|
34
|
+
layer.style.cssText = "position:fixed;inset:0;z-index:2147483646;pointer-events:none;contain:strict;";
|
|
35
|
+
const label = doc.createElement("div");
|
|
36
|
+
label.style.cssText = "position:absolute;padding:1px 5px;border-radius:3px;background:#5eead4;color:#07131a;font:11px/1.5 ui-monospace,monospace;white-space:nowrap;";
|
|
37
|
+
layer.append(label);
|
|
38
|
+
doc.body.appendChild(layer);
|
|
39
|
+
return { layer, boxes: [], label };
|
|
40
|
+
}
|
|
41
|
+
function boxIn(overlay2, index) {
|
|
42
|
+
const held = overlay2.boxes[index];
|
|
43
|
+
if (held) return held;
|
|
44
|
+
const box = overlay2.layer.ownerDocument.createElement("div");
|
|
45
|
+
box.style.cssText = "position:absolute;border:1px solid #5eead4;background:rgba(94,234,212,.16);border-radius:2px;transition:none;";
|
|
46
|
+
overlay2.layer.append(box);
|
|
47
|
+
overlay2.boxes.push(box);
|
|
48
|
+
return box;
|
|
49
|
+
}
|
|
50
|
+
function showHighlight(target, text) {
|
|
51
|
+
const elements = (Array.isArray(target) ? target : [target]).filter(
|
|
52
|
+
(el) => el?.isConnected
|
|
53
|
+
);
|
|
54
|
+
const first = elements[0];
|
|
55
|
+
const doc = first?.ownerDocument;
|
|
56
|
+
if (!doc?.body) {
|
|
57
|
+
hideHighlight();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (!overlay || overlay.layer.ownerDocument !== doc || !overlay.layer.isConnected) {
|
|
61
|
+
overlay = build(doc);
|
|
62
|
+
}
|
|
63
|
+
const { label, layer } = overlay;
|
|
64
|
+
layer.style.display = "";
|
|
65
|
+
let top = Infinity;
|
|
66
|
+
let left = Infinity;
|
|
67
|
+
let bottom = 0;
|
|
68
|
+
elements.forEach((element, index) => {
|
|
69
|
+
const rect = element.getBoundingClientRect();
|
|
70
|
+
const box = boxIn(overlay, index);
|
|
71
|
+
box.style.display = "";
|
|
72
|
+
box.style.left = `${rect.left}px`;
|
|
73
|
+
box.style.top = `${rect.top}px`;
|
|
74
|
+
box.style.width = `${rect.width}px`;
|
|
75
|
+
box.style.height = `${rect.height}px`;
|
|
76
|
+
top = Math.min(top, rect.top);
|
|
77
|
+
left = Math.min(left, rect.left);
|
|
78
|
+
bottom = Math.max(bottom, rect.bottom);
|
|
79
|
+
});
|
|
80
|
+
for (let i = elements.length; i < overlay.boxes.length; i++) {
|
|
81
|
+
overlay.boxes[i].style.display = "none";
|
|
82
|
+
}
|
|
83
|
+
if (!text) {
|
|
84
|
+
label.style.display = "none";
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
label.style.display = "";
|
|
88
|
+
label.textContent = text;
|
|
89
|
+
label.style.left = `${Math.max(2, left)}px`;
|
|
90
|
+
label.style.top = top >= 20 ? `${top - 18}px` : `${bottom + 4}px`;
|
|
91
|
+
}
|
|
92
|
+
function hideHighlight() {
|
|
93
|
+
if (overlay) overlay.layer.style.display = "none";
|
|
94
|
+
}
|
|
95
|
+
function removeHighlight() {
|
|
96
|
+
overlay?.layer.remove();
|
|
97
|
+
overlay = null;
|
|
98
|
+
}
|
|
99
|
+
function startPicking(options) {
|
|
100
|
+
const doc = options.document ?? globalThis.document;
|
|
101
|
+
if (!doc?.body) return () => {
|
|
102
|
+
};
|
|
103
|
+
const was = doc.body.style.cursor;
|
|
104
|
+
doc.body.style.cursor = "crosshair";
|
|
105
|
+
const under = (event) => {
|
|
106
|
+
const target = event.target;
|
|
107
|
+
return target?.closest?.(`#${LAYER}`) ? null : target;
|
|
108
|
+
};
|
|
109
|
+
const move = (event) => {
|
|
110
|
+
const element = under(event);
|
|
111
|
+
const id = options.nodeAt(element);
|
|
112
|
+
if (element && id !== void 0) showHighlight(element, options.describe?.(id, element));
|
|
113
|
+
else hideHighlight();
|
|
114
|
+
};
|
|
115
|
+
const click = (event) => {
|
|
116
|
+
event.preventDefault();
|
|
117
|
+
event.stopPropagation();
|
|
118
|
+
const target = under(event);
|
|
119
|
+
const id = options.nodeAt(target);
|
|
120
|
+
if (!options.sticky) stop();
|
|
121
|
+
if (id !== void 0) options.onPick(id, target);
|
|
122
|
+
else if (!options.sticky) options.onCancel?.();
|
|
123
|
+
};
|
|
124
|
+
const key = (event) => {
|
|
125
|
+
if (event.key !== "Escape") return;
|
|
126
|
+
stop();
|
|
127
|
+
options.onCancel?.();
|
|
128
|
+
};
|
|
129
|
+
const stop = () => {
|
|
130
|
+
doc.body.style.cursor = was;
|
|
131
|
+
doc.removeEventListener("pointermove", move, true);
|
|
132
|
+
doc.removeEventListener("click", click, true);
|
|
133
|
+
doc.removeEventListener("keydown", key, true);
|
|
134
|
+
hideHighlight();
|
|
135
|
+
};
|
|
136
|
+
doc.addEventListener("pointermove", move, true);
|
|
137
|
+
doc.addEventListener("click", click, true);
|
|
138
|
+
doc.addEventListener("keydown", key, true);
|
|
139
|
+
return stop;
|
|
140
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Showing where something is on the page.
|
|
3
|
+
*
|
|
4
|
+
* Two things use this. Hovering a node in a panel draws a box round what it writes into, and
|
|
5
|
+
* picking works the other way: move over the page and the box follows whatever is under the
|
|
6
|
+
* pointer, until a click says which one.
|
|
7
|
+
*
|
|
8
|
+
* The overlay is not part of the application: it sits in its own fixed layer, takes no
|
|
9
|
+
* pointer events, and is torn down with `stop`. Nothing it holds outlives a call.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Draw over everything `target` covers.
|
|
13
|
+
*
|
|
14
|
+
* A box each, rather than one around the lot: a component's regions are usually not
|
|
15
|
+
* adjacent, and a rectangle spanning them covers plenty it has nothing to do with. The
|
|
16
|
+
* label sits above the topmost.
|
|
17
|
+
*
|
|
18
|
+
* Called repeatedly while a pointer moves, so the boxes are reused rather than remade.
|
|
19
|
+
*/
|
|
20
|
+
export declare function showHighlight(target: Element | readonly Element[], text?: string): void;
|
|
21
|
+
export declare function hideHighlight(): void;
|
|
22
|
+
/** Take the overlay off the page. Safe to call when there is none. */
|
|
23
|
+
export declare function removeHighlight(): void;
|
|
24
|
+
export interface PickOptions {
|
|
25
|
+
/** The node under the pointer, for the box's label and for what a click reports. */
|
|
26
|
+
nodeAt: (element: Element | null) => number | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* What the box is labelled. The element comes too, because the owning tag alone reads
|
|
29
|
+
* `App` over every heading and input that component wrote.
|
|
30
|
+
*/
|
|
31
|
+
describe?: (id: number, element: Element) => string;
|
|
32
|
+
/**
|
|
33
|
+
* A click on something the graph knows. Picking stops first unless `sticky`.
|
|
34
|
+
*
|
|
35
|
+
* The element comes too: the owning tag alone is too coarse to be useful, since every
|
|
36
|
+
* `<h3>` and `<input>` a component wrote answers with that component.
|
|
37
|
+
*/
|
|
38
|
+
onPick: (id: number, element: Element | null) => void;
|
|
39
|
+
/** Picking has ended: escape, or a click on nothing when it is not sticky. */
|
|
40
|
+
onCancel?: () => void;
|
|
41
|
+
/**
|
|
42
|
+
* Stay armed after a pick, so several elements can be chosen in a row. Escape and the
|
|
43
|
+
* returned stop still end it, and a click on nothing is ignored rather than cancelling.
|
|
44
|
+
*/
|
|
45
|
+
sticky?: boolean;
|
|
46
|
+
/** Defaults to the page this module is running in. */
|
|
47
|
+
document?: Document;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Follow the pointer until something is clicked.
|
|
51
|
+
*
|
|
52
|
+
* Listeners are on the capture phase so the application never sees the click that chose an
|
|
53
|
+
* element, since picking a button should not press it. Returns a function that stops early.
|
|
54
|
+
*/
|
|
55
|
+
export declare function startPicking(options: PickOptions): () => void;
|
|
56
|
+
//# sourceMappingURL=highlight.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"highlight.d.ts","sourceRoot":"","sources":["../src/highlight.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAyCH;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,OAAO,EAAE,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CA6CvF;AAED,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAED,sEAAsE;AACtE,wBAAgB,eAAe,IAAI,IAAI,CAGtC;AAED,MAAM,WAAW,WAAW;IAC1B,oFAAoF;IACpF,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,KAAK,MAAM,GAAG,SAAS,CAAC;IACxD;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;IACpD;;;;;OAKG;IACH,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC;IACtD,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,sDAAsD;IACtD,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,IAAI,CAkD7D"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Showing where something is on the page.
|
|
3
|
+
*
|
|
4
|
+
* Two things use this. Hovering a node in a panel draws a box round what it writes into, and
|
|
5
|
+
* picking works the other way: move over the page and the box follows whatever is under the
|
|
6
|
+
* pointer, until a click says which one.
|
|
7
|
+
*
|
|
8
|
+
* The overlay is not part of the application: it sits in its own fixed layer, takes no
|
|
9
|
+
* pointer events, and is torn down with `stop`. Nothing it holds outlives a call.
|
|
10
|
+
*/
|
|
11
|
+
const LAYER = 'fx-highlight-layer';
|
|
12
|
+
let overlay = null;
|
|
13
|
+
function build(doc) {
|
|
14
|
+
const layer = doc.createElement('div');
|
|
15
|
+
layer.id = LAYER;
|
|
16
|
+
layer.style.cssText =
|
|
17
|
+
'position:fixed;inset:0;z-index:2147483646;pointer-events:none;contain:strict;';
|
|
18
|
+
const label = doc.createElement('div');
|
|
19
|
+
label.style.cssText =
|
|
20
|
+
'position:absolute;padding:1px 5px;border-radius:3px;background:#5eead4;color:#07131a;' +
|
|
21
|
+
"font:11px/1.5 ui-monospace,monospace;white-space:nowrap;";
|
|
22
|
+
layer.append(label);
|
|
23
|
+
doc.body.appendChild(layer);
|
|
24
|
+
return { layer, boxes: [], label };
|
|
25
|
+
}
|
|
26
|
+
function boxIn(overlay, index) {
|
|
27
|
+
const held = overlay.boxes[index];
|
|
28
|
+
if (held)
|
|
29
|
+
return held;
|
|
30
|
+
const box = overlay.layer.ownerDocument.createElement('div');
|
|
31
|
+
box.style.cssText =
|
|
32
|
+
'position:absolute;border:1px solid #5eead4;background:rgba(94,234,212,.16);' +
|
|
33
|
+
'border-radius:2px;transition:none;';
|
|
34
|
+
overlay.layer.append(box);
|
|
35
|
+
overlay.boxes.push(box);
|
|
36
|
+
return box;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Draw over everything `target` covers.
|
|
40
|
+
*
|
|
41
|
+
* A box each, rather than one around the lot: a component's regions are usually not
|
|
42
|
+
* adjacent, and a rectangle spanning them covers plenty it has nothing to do with. The
|
|
43
|
+
* label sits above the topmost.
|
|
44
|
+
*
|
|
45
|
+
* Called repeatedly while a pointer moves, so the boxes are reused rather than remade.
|
|
46
|
+
*/
|
|
47
|
+
export function showHighlight(target, text) {
|
|
48
|
+
const elements = (Array.isArray(target) ? target : [target]).filter((el) => el?.isConnected);
|
|
49
|
+
const first = elements[0];
|
|
50
|
+
const doc = first?.ownerDocument;
|
|
51
|
+
if (!doc?.body) {
|
|
52
|
+
hideHighlight();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
// Rebuilt when the document changed, or when the page removed the layer from under us.
|
|
56
|
+
if (!overlay || overlay.layer.ownerDocument !== doc || !overlay.layer.isConnected) {
|
|
57
|
+
overlay = build(doc);
|
|
58
|
+
}
|
|
59
|
+
const { label, layer } = overlay;
|
|
60
|
+
layer.style.display = '';
|
|
61
|
+
let top = Infinity;
|
|
62
|
+
let left = Infinity;
|
|
63
|
+
let bottom = 0;
|
|
64
|
+
elements.forEach((element, index) => {
|
|
65
|
+
const rect = element.getBoundingClientRect();
|
|
66
|
+
const box = boxIn(overlay, index);
|
|
67
|
+
box.style.display = '';
|
|
68
|
+
box.style.left = `${rect.left}px`;
|
|
69
|
+
box.style.top = `${rect.top}px`;
|
|
70
|
+
box.style.width = `${rect.width}px`;
|
|
71
|
+
box.style.height = `${rect.height}px`;
|
|
72
|
+
top = Math.min(top, rect.top);
|
|
73
|
+
left = Math.min(left, rect.left);
|
|
74
|
+
bottom = Math.max(bottom, rect.bottom);
|
|
75
|
+
});
|
|
76
|
+
// Whatever the last target needed and this one does not.
|
|
77
|
+
for (let i = elements.length; i < overlay.boxes.length; i++) {
|
|
78
|
+
overlay.boxes[i].style.display = 'none';
|
|
79
|
+
}
|
|
80
|
+
if (!text) {
|
|
81
|
+
label.style.display = 'none';
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
label.style.display = '';
|
|
85
|
+
label.textContent = text;
|
|
86
|
+
label.style.left = `${Math.max(2, left)}px`;
|
|
87
|
+
label.style.top = top >= 20 ? `${top - 18}px` : `${bottom + 4}px`;
|
|
88
|
+
}
|
|
89
|
+
export function hideHighlight() {
|
|
90
|
+
if (overlay)
|
|
91
|
+
overlay.layer.style.display = 'none';
|
|
92
|
+
}
|
|
93
|
+
/** Take the overlay off the page. Safe to call when there is none. */
|
|
94
|
+
export function removeHighlight() {
|
|
95
|
+
overlay?.layer.remove();
|
|
96
|
+
overlay = null;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Follow the pointer until something is clicked.
|
|
100
|
+
*
|
|
101
|
+
* Listeners are on the capture phase so the application never sees the click that chose an
|
|
102
|
+
* element, since picking a button should not press it. Returns a function that stops early.
|
|
103
|
+
*/
|
|
104
|
+
export function startPicking(options) {
|
|
105
|
+
const doc = options.document ?? globalThis.document;
|
|
106
|
+
if (!doc?.body)
|
|
107
|
+
return () => { };
|
|
108
|
+
const was = doc.body.style.cursor;
|
|
109
|
+
doc.body.style.cursor = 'crosshair';
|
|
110
|
+
const under = (event) => {
|
|
111
|
+
const target = event.target;
|
|
112
|
+
// Inside the overlay is not a pick; it should not be hit anyway, but a page can move it.
|
|
113
|
+
return target?.closest?.(`#${LAYER}`) ? null : target;
|
|
114
|
+
};
|
|
115
|
+
const move = (event) => {
|
|
116
|
+
const element = under(event);
|
|
117
|
+
const id = options.nodeAt(element);
|
|
118
|
+
if (element && id !== undefined)
|
|
119
|
+
showHighlight(element, options.describe?.(id, element));
|
|
120
|
+
else
|
|
121
|
+
hideHighlight();
|
|
122
|
+
};
|
|
123
|
+
const click = (event) => {
|
|
124
|
+
event.preventDefault();
|
|
125
|
+
event.stopPropagation();
|
|
126
|
+
const target = under(event);
|
|
127
|
+
const id = options.nodeAt(target);
|
|
128
|
+
if (!options.sticky)
|
|
129
|
+
stop();
|
|
130
|
+
if (id !== undefined)
|
|
131
|
+
options.onPick(id, target);
|
|
132
|
+
// Only a real end reports a cancel. A sticky miss leaves the pointer armed, so saying
|
|
133
|
+
// it ended would put the toolbar out of step with the listeners still attached.
|
|
134
|
+
else if (!options.sticky)
|
|
135
|
+
options.onCancel?.();
|
|
136
|
+
};
|
|
137
|
+
const key = (event) => {
|
|
138
|
+
if (event.key !== 'Escape')
|
|
139
|
+
return;
|
|
140
|
+
stop();
|
|
141
|
+
options.onCancel?.();
|
|
142
|
+
};
|
|
143
|
+
const stop = () => {
|
|
144
|
+
doc.body.style.cursor = was;
|
|
145
|
+
doc.removeEventListener('pointermove', move, true);
|
|
146
|
+
doc.removeEventListener('click', click, true);
|
|
147
|
+
doc.removeEventListener('keydown', key, true);
|
|
148
|
+
hideHighlight();
|
|
149
|
+
};
|
|
150
|
+
doc.addEventListener('pointermove', move, true);
|
|
151
|
+
doc.addEventListener('click', click, true);
|
|
152
|
+
doc.addEventListener('keydown', key, true);
|
|
153
|
+
return stop;
|
|
154
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// src/highlight.ts
|
|
2
|
+
var LAYER = "fx-highlight-layer";
|
|
3
|
+
var overlay = null;
|
|
4
|
+
function build(doc) {
|
|
5
|
+
const layer = doc.createElement("div");
|
|
6
|
+
layer.id = LAYER;
|
|
7
|
+
layer.style.cssText = "position:fixed;inset:0;z-index:2147483646;pointer-events:none;contain:strict;";
|
|
8
|
+
const label = doc.createElement("div");
|
|
9
|
+
label.style.cssText = "position:absolute;padding:1px 5px;border-radius:3px;background:#5eead4;color:#07131a;font:11px/1.5 ui-monospace,monospace;white-space:nowrap;";
|
|
10
|
+
layer.append(label);
|
|
11
|
+
doc.body.appendChild(layer);
|
|
12
|
+
return { layer, boxes: [], label };
|
|
13
|
+
}
|
|
14
|
+
function boxIn(overlay2, index) {
|
|
15
|
+
const held = overlay2.boxes[index];
|
|
16
|
+
if (held) return held;
|
|
17
|
+
const box = overlay2.layer.ownerDocument.createElement("div");
|
|
18
|
+
box.style.cssText = "position:absolute;border:1px solid #5eead4;background:rgba(94,234,212,.16);border-radius:2px;transition:none;";
|
|
19
|
+
overlay2.layer.append(box);
|
|
20
|
+
overlay2.boxes.push(box);
|
|
21
|
+
return box;
|
|
22
|
+
}
|
|
23
|
+
function showHighlight(target, text) {
|
|
24
|
+
const elements = (Array.isArray(target) ? target : [target]).filter(
|
|
25
|
+
(el) => el?.isConnected
|
|
26
|
+
);
|
|
27
|
+
const first = elements[0];
|
|
28
|
+
const doc = first?.ownerDocument;
|
|
29
|
+
if (!doc?.body) {
|
|
30
|
+
hideHighlight();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (!overlay || overlay.layer.ownerDocument !== doc || !overlay.layer.isConnected) {
|
|
34
|
+
overlay = build(doc);
|
|
35
|
+
}
|
|
36
|
+
const { label, layer } = overlay;
|
|
37
|
+
layer.style.display = "";
|
|
38
|
+
let top = Infinity;
|
|
39
|
+
let left = Infinity;
|
|
40
|
+
let bottom = 0;
|
|
41
|
+
elements.forEach((element, index) => {
|
|
42
|
+
const rect = element.getBoundingClientRect();
|
|
43
|
+
const box = boxIn(overlay, index);
|
|
44
|
+
box.style.display = "";
|
|
45
|
+
box.style.left = `${rect.left}px`;
|
|
46
|
+
box.style.top = `${rect.top}px`;
|
|
47
|
+
box.style.width = `${rect.width}px`;
|
|
48
|
+
box.style.height = `${rect.height}px`;
|
|
49
|
+
top = Math.min(top, rect.top);
|
|
50
|
+
left = Math.min(left, rect.left);
|
|
51
|
+
bottom = Math.max(bottom, rect.bottom);
|
|
52
|
+
});
|
|
53
|
+
for (let i = elements.length; i < overlay.boxes.length; i++) {
|
|
54
|
+
overlay.boxes[i].style.display = "none";
|
|
55
|
+
}
|
|
56
|
+
if (!text) {
|
|
57
|
+
label.style.display = "none";
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
label.style.display = "";
|
|
61
|
+
label.textContent = text;
|
|
62
|
+
label.style.left = `${Math.max(2, left)}px`;
|
|
63
|
+
label.style.top = top >= 20 ? `${top - 18}px` : `${bottom + 4}px`;
|
|
64
|
+
}
|
|
65
|
+
function hideHighlight() {
|
|
66
|
+
if (overlay) overlay.layer.style.display = "none";
|
|
67
|
+
}
|
|
68
|
+
function removeHighlight() {
|
|
69
|
+
overlay?.layer.remove();
|
|
70
|
+
overlay = null;
|
|
71
|
+
}
|
|
72
|
+
function startPicking(options) {
|
|
73
|
+
const doc = options.document ?? globalThis.document;
|
|
74
|
+
if (!doc?.body) return () => {
|
|
75
|
+
};
|
|
76
|
+
const was = doc.body.style.cursor;
|
|
77
|
+
doc.body.style.cursor = "crosshair";
|
|
78
|
+
const under = (event) => {
|
|
79
|
+
const target = event.target;
|
|
80
|
+
return target?.closest?.(`#${LAYER}`) ? null : target;
|
|
81
|
+
};
|
|
82
|
+
const move = (event) => {
|
|
83
|
+
const element = under(event);
|
|
84
|
+
const id = options.nodeAt(element);
|
|
85
|
+
if (element && id !== void 0) showHighlight(element, options.describe?.(id, element));
|
|
86
|
+
else hideHighlight();
|
|
87
|
+
};
|
|
88
|
+
const click = (event) => {
|
|
89
|
+
event.preventDefault();
|
|
90
|
+
event.stopPropagation();
|
|
91
|
+
const target = under(event);
|
|
92
|
+
const id = options.nodeAt(target);
|
|
93
|
+
if (!options.sticky) stop();
|
|
94
|
+
if (id !== void 0) options.onPick(id, target);
|
|
95
|
+
else if (!options.sticky) options.onCancel?.();
|
|
96
|
+
};
|
|
97
|
+
const key = (event) => {
|
|
98
|
+
if (event.key !== "Escape") return;
|
|
99
|
+
stop();
|
|
100
|
+
options.onCancel?.();
|
|
101
|
+
};
|
|
102
|
+
const stop = () => {
|
|
103
|
+
doc.body.style.cursor = was;
|
|
104
|
+
doc.removeEventListener("pointermove", move, true);
|
|
105
|
+
doc.removeEventListener("click", click, true);
|
|
106
|
+
doc.removeEventListener("keydown", key, true);
|
|
107
|
+
hideHighlight();
|
|
108
|
+
};
|
|
109
|
+
doc.addEventListener("pointermove", move, true);
|
|
110
|
+
doc.addEventListener("click", click, true);
|
|
111
|
+
doc.addEventListener("keydown", key, true);
|
|
112
|
+
return stop;
|
|
113
|
+
}
|
|
114
|
+
export {
|
|
115
|
+
hideHighlight,
|
|
116
|
+
removeHighlight,
|
|
117
|
+
showHighlight,
|
|
118
|
+
startPicking
|
|
119
|
+
};
|
package/dist/history.cjs
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
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/history.ts
|
|
21
|
+
var history_exports = {};
|
|
22
|
+
__export(history_exports, {
|
|
23
|
+
createHistory: () => createHistory,
|
|
24
|
+
toCommits: () => toCommits
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(history_exports);
|
|
27
|
+
var OFF = {
|
|
28
|
+
wrote() {
|
|
29
|
+
},
|
|
30
|
+
ran() {
|
|
31
|
+
},
|
|
32
|
+
created() {
|
|
33
|
+
},
|
|
34
|
+
disposed() {
|
|
35
|
+
},
|
|
36
|
+
take: () => [],
|
|
37
|
+
dropped: 0,
|
|
38
|
+
clear() {
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
function createHistory(limit) {
|
|
42
|
+
if (limit <= 0) return OFF;
|
|
43
|
+
let events = [];
|
|
44
|
+
let seq = 0;
|
|
45
|
+
let commit = 0;
|
|
46
|
+
let dropped = 0;
|
|
47
|
+
const push = (event) => {
|
|
48
|
+
events.push({ ...event, seq: seq++, t: Date.now(), commit });
|
|
49
|
+
if (events.length > limit) {
|
|
50
|
+
dropped += events.length - limit;
|
|
51
|
+
events = events.slice(-limit);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
return {
|
|
55
|
+
wrote(id, by, detail) {
|
|
56
|
+
if (by === void 0) commit++;
|
|
57
|
+
push({ kind: "write", id, by, ...detail });
|
|
58
|
+
},
|
|
59
|
+
ran(id, by) {
|
|
60
|
+
push({ kind: "ran", id, by });
|
|
61
|
+
},
|
|
62
|
+
created(id, by, label) {
|
|
63
|
+
push({ kind: "created", id, by, label });
|
|
64
|
+
},
|
|
65
|
+
disposed(id, label) {
|
|
66
|
+
push({ kind: "disposed", id, label });
|
|
67
|
+
},
|
|
68
|
+
take() {
|
|
69
|
+
const taken = events;
|
|
70
|
+
events = [];
|
|
71
|
+
return taken;
|
|
72
|
+
},
|
|
73
|
+
get dropped() {
|
|
74
|
+
return dropped;
|
|
75
|
+
},
|
|
76
|
+
clear() {
|
|
77
|
+
events = [];
|
|
78
|
+
dropped = 0;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function toCommits(events) {
|
|
83
|
+
const byNumber = /* @__PURE__ */ new Map();
|
|
84
|
+
for (const event of events) {
|
|
85
|
+
const bucket = byNumber.get(event.commit);
|
|
86
|
+
if (bucket) bucket.push(event);
|
|
87
|
+
else byNumber.set(event.commit, [event]);
|
|
88
|
+
}
|
|
89
|
+
return [...byNumber.entries()].sort((a, b) => a[0] - b[0]).map(([commit, group]) => ({
|
|
90
|
+
commit,
|
|
91
|
+
t: group[0].t,
|
|
92
|
+
events: group,
|
|
93
|
+
cause: group.find((e) => e.kind === "write" && e.by === void 0)
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { ValueChange } from './diff.js';
|
|
2
|
+
export type GraphEventKind = 'write' | 'ran' | 'created' | 'disposed';
|
|
3
|
+
export interface GraphEvent {
|
|
4
|
+
/** Monotonic across the session, so a consumer folding deltas never reorders them. */
|
|
5
|
+
readonly seq: number;
|
|
6
|
+
/** Producer clock, matching the snapshot's. */
|
|
7
|
+
readonly t: number;
|
|
8
|
+
readonly kind: GraphEventKind;
|
|
9
|
+
/** The node it happened to. */
|
|
10
|
+
readonly id: number;
|
|
11
|
+
/** What caused it. Absent on a write means nothing was running: an event handler did it. */
|
|
12
|
+
readonly by?: number;
|
|
13
|
+
/** One write from outside and everything it caused. Commit 0 is the first render. */
|
|
14
|
+
readonly commit: number;
|
|
15
|
+
/** Writes only: the value before and after, already formatted and short. */
|
|
16
|
+
readonly from?: string;
|
|
17
|
+
readonly to?: string;
|
|
18
|
+
/** Writes only, and only when the two sides differ structurally: which entries moved. */
|
|
19
|
+
readonly change?: ValueChange;
|
|
20
|
+
/**
|
|
21
|
+
* The name at the time. A consumer normally reads it off the graph, but a disposed node is
|
|
22
|
+
* no longer there — and a list re-render is mostly disposals — so it travels with the event.
|
|
23
|
+
*/
|
|
24
|
+
readonly label?: string;
|
|
25
|
+
}
|
|
26
|
+
/** What a write is worth recording about, beyond who did it. */
|
|
27
|
+
export interface WriteDetail {
|
|
28
|
+
from?: string;
|
|
29
|
+
to?: string;
|
|
30
|
+
change?: ValueChange;
|
|
31
|
+
label?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface History {
|
|
34
|
+
wrote(id: number, by: number | undefined, detail?: WriteDetail): void;
|
|
35
|
+
ran(id: number, by?: number): void;
|
|
36
|
+
created(id: number, by?: number, label?: string): void;
|
|
37
|
+
disposed(id: number, label?: string): void;
|
|
38
|
+
/** Everything since the last call. Draining is what keeps a producer nobody polls bounded. */
|
|
39
|
+
take(): GraphEvent[];
|
|
40
|
+
/** How many events were dropped for being older than the limit. */
|
|
41
|
+
readonly dropped: number;
|
|
42
|
+
clear(): void;
|
|
43
|
+
}
|
|
44
|
+
/** Keep the last `limit`. An app nobody is polling still runs effects. */
|
|
45
|
+
export declare function createHistory(limit: number): History;
|
|
46
|
+
/** One commit, as a reader of the timeline sees it. */
|
|
47
|
+
export interface Commit {
|
|
48
|
+
readonly commit: number;
|
|
49
|
+
readonly t: number;
|
|
50
|
+
readonly events: GraphEvent[];
|
|
51
|
+
/** The write that opened it, if the buffer still holds it. */
|
|
52
|
+
readonly cause?: GraphEvent;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Oldest first. A commit whose opening write has aged out still groups — its events carry the
|
|
56
|
+
* number, and a partial commit beats dropping the runs after it.
|
|
57
|
+
*/
|
|
58
|
+
export declare function toCommits(events: readonly GraphEvent[]): Commit[];
|
|
59
|
+
//# sourceMappingURL=history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,KAAK,GAAG,SAAS,GAAG,UAAU,CAAC;AAEtE,MAAM,WAAW,UAAU;IACzB,sFAAsF;IACtF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,qFAAqF;IACrF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,yFAAyF;IACzF,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,gEAAgE;AAChE,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACtE,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvD,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,8FAA8F;IAC9F,IAAI,IAAI,UAAU,EAAE,CAAC;IACrB,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,KAAK,IAAI,IAAI,CAAC;CACf;AAaD,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CA4CpD;AAED,uDAAuD;AACvD,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC;IAC9B,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,GAAG,MAAM,EAAE,CAejE"}
|