@fluixi/devtools 0.2.0-alpha.2 → 0.2.0-alpha.3
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.d.ts +22 -0
- package/dist/callsite.d.ts.map +1 -0
- package/dist/callsite.js +82 -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/copy.d.ts +9 -0
- package/dist/copy.d.ts.map +1 -0
- package/dist/copy.js +52 -0
- package/dist/describe.d.ts +3 -0
- package/dist/describe.d.ts.map +1 -0
- package/dist/describe.js +47 -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/diff.d.ts +31 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +132 -0
- package/dist/dom.d.ts +81 -0
- package/dist/dom.d.ts.map +1 -0
- package/dist/dom.js +269 -0
- package/dist/export.d.ts +55 -0
- package/dist/export.d.ts.map +1 -0
- package/dist/export.js +90 -0
- package/dist/float.d.ts +54 -0
- package/dist/float.d.ts.map +1 -0
- package/dist/float.js +256 -0
- package/dist/format.d.ts +16 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +188 -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/highlight.d.ts +56 -0
- package/dist/highlight.d.ts.map +1 -0
- package/dist/highlight.js +154 -0
- package/dist/history.d.ts +59 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +85 -0
- package/dist/hook.d.ts +60 -0
- package/dist/hook.d.ts.map +1 -0
- package/dist/hook.js +142 -0
- package/dist/index.d.ts +44 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -1
- package/dist/inspector.d.ts +60 -0
- package/dist/inspector.d.ts.map +1 -0
- package/dist/inspector.js +415 -0
- package/dist/instrument.d.ts +147 -5
- package/dist/instrument.d.ts.map +1 -1
- package/dist/instrument.js +164 -44
- 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/menu.d.ts +37 -0
- package/dist/menu.d.ts.map +1 -0
- package/dist/menu.js +125 -0
- package/dist/observe.d.ts +80 -0
- package/dist/observe.d.ts.map +1 -0
- package/dist/observe.js +893 -0
- package/dist/palette.d.ts +11 -0
- package/dist/palette.d.ts.map +1 -0
- package/dist/palette.js +27 -0
- package/dist/path.d.ts +19 -0
- package/dist/path.d.ts.map +1 -0
- package/dist/path.js +49 -0
- package/dist/plugin.d.ts +121 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +74 -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/directives.d.ts +25 -0
- package/dist/plugins/directives.d.ts.map +1 -0
- package/dist/plugins/directives.js +78 -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/source.d.ts +72 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +153 -0
- package/dist/timeline.d.ts +30 -0
- package/dist/timeline.d.ts.map +1 -0
- package/dist/timeline.js +271 -0
- package/dist/tree.d.ts +128 -0
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +645 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- 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/wire.d.ts +100 -0
- package/dist/wire.d.ts.map +1 -0
- package/dist/wire.js +93 -0
- package/package.json +7 -2
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/** Every kind a graph can hold, in the order they are offered. */
|
|
2
|
+
export const FILTERABLE_KINDS = [
|
|
3
|
+
'state', 'memo', 'effect', 'store', 'resource', 'component', 'provider', 'control', 'router', 'handler',
|
|
4
|
+
'context', 'directive',
|
|
5
|
+
];
|
|
6
|
+
/** Only `handler` needs renaming; the other kinds read fine as they are. */
|
|
7
|
+
const LABEL = { handler: 'route' };
|
|
8
|
+
/**
|
|
9
|
+
* Builds the control inside `host`. Call `destroy` to remove it — it holds a document
|
|
10
|
+
* listener for closing the panel on an outside click.
|
|
11
|
+
*/
|
|
12
|
+
export function createKindFilter(host, options) {
|
|
13
|
+
const doc = host.ownerDocument;
|
|
14
|
+
const kinds = options.kinds ?? FILTERABLE_KINDS;
|
|
15
|
+
const on = new Set(kinds);
|
|
16
|
+
const root = doc.createElement('div');
|
|
17
|
+
root.className = 'fx-kinds';
|
|
18
|
+
const button = doc.createElement('button');
|
|
19
|
+
button.type = 'button';
|
|
20
|
+
button.className = 'fx-kinds-button fx-dropdown-btn';
|
|
21
|
+
button.setAttribute('aria-haspopup', 'true');
|
|
22
|
+
button.setAttribute('aria-expanded', 'false');
|
|
23
|
+
button.title = 'Choose which kinds of node the graph draws';
|
|
24
|
+
const caret = doc.createElement('div');
|
|
25
|
+
caret.className = 'fx-dropdown-caret';
|
|
26
|
+
const panel = doc.createElement('div');
|
|
27
|
+
panel.className = 'fx-kinds-panel';
|
|
28
|
+
if (options.panelClass) {
|
|
29
|
+
panel.classList.add(...options.panelClass.split(/\s+/).filter((c) => c));
|
|
30
|
+
}
|
|
31
|
+
panel.hidden = true;
|
|
32
|
+
const all = doc.createElement('input');
|
|
33
|
+
all.type = 'checkbox';
|
|
34
|
+
const allRow = doc.createElement('label');
|
|
35
|
+
allRow.className = 'fx-kinds-all';
|
|
36
|
+
allRow.append(all, doc.createTextNode('all'));
|
|
37
|
+
const boxes = new Map();
|
|
38
|
+
for (const kind of kinds) {
|
|
39
|
+
const box = doc.createElement('input');
|
|
40
|
+
box.type = 'checkbox';
|
|
41
|
+
box.checked = true;
|
|
42
|
+
const row = doc.createElement('label');
|
|
43
|
+
row.append(box, doc.createTextNode(LABEL[kind] ?? kind));
|
|
44
|
+
panel.append(row);
|
|
45
|
+
boxes.set(kind, box);
|
|
46
|
+
}
|
|
47
|
+
panel.prepend(allRow);
|
|
48
|
+
root.append(button, panel);
|
|
49
|
+
host.append(root);
|
|
50
|
+
const everything = () => on.size === kinds.length;
|
|
51
|
+
// Read back in the order they are offered: a Set re-orders as entries come and go.
|
|
52
|
+
const chosen = () => kinds.filter((kind) => on.has(kind));
|
|
53
|
+
function paint() {
|
|
54
|
+
const name = options.label ?? 'Kinds';
|
|
55
|
+
button.textContent = everything() ? name : `${name} · ${on.size}`;
|
|
56
|
+
button.classList.toggle('on', !everything());
|
|
57
|
+
all.checked = everything();
|
|
58
|
+
button.appendChild(caret);
|
|
59
|
+
// Partly selected: show the box as indeterminate rather than guessing a state.
|
|
60
|
+
all.indeterminate = on.size > 0 && !everything();
|
|
61
|
+
for (const [kind, box] of boxes)
|
|
62
|
+
box.checked = on.has(kind);
|
|
63
|
+
}
|
|
64
|
+
function report() {
|
|
65
|
+
options.onChange(everything() ? null : chosen());
|
|
66
|
+
}
|
|
67
|
+
for (const [kind, box] of boxes) {
|
|
68
|
+
box.addEventListener('change', () => {
|
|
69
|
+
if (box.checked)
|
|
70
|
+
on.add(kind);
|
|
71
|
+
else
|
|
72
|
+
on.delete(kind);
|
|
73
|
+
paint();
|
|
74
|
+
report();
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
all.addEventListener('change', () => {
|
|
78
|
+
// Unticking would select nothing, leaving an empty graph with no obvious way back,
|
|
79
|
+
// so either direction turns everything on.
|
|
80
|
+
for (const kind of kinds)
|
|
81
|
+
on.add(kind);
|
|
82
|
+
paint();
|
|
83
|
+
report();
|
|
84
|
+
});
|
|
85
|
+
const close = () => {
|
|
86
|
+
panel.hidden = true;
|
|
87
|
+
button.setAttribute('aria-expanded', 'false');
|
|
88
|
+
};
|
|
89
|
+
button.addEventListener('click', (event) => {
|
|
90
|
+
event.stopPropagation();
|
|
91
|
+
panel.hidden = !panel.hidden;
|
|
92
|
+
button.setAttribute('aria-expanded', String(!panel.hidden));
|
|
93
|
+
});
|
|
94
|
+
// Stop clicks inside the panel reaching the document listener, which would close it.
|
|
95
|
+
panel.addEventListener('click', (event) => event.stopPropagation());
|
|
96
|
+
const away = () => close();
|
|
97
|
+
const key = (event) => {
|
|
98
|
+
if (event.key === 'Escape')
|
|
99
|
+
close();
|
|
100
|
+
};
|
|
101
|
+
doc.addEventListener('click', away);
|
|
102
|
+
doc.addEventListener('keydown', key);
|
|
103
|
+
paint();
|
|
104
|
+
return {
|
|
105
|
+
get selected() {
|
|
106
|
+
return chosen();
|
|
107
|
+
},
|
|
108
|
+
select(next) {
|
|
109
|
+
on.clear();
|
|
110
|
+
for (const kind of next ?? kinds)
|
|
111
|
+
on.add(kind);
|
|
112
|
+
paint();
|
|
113
|
+
},
|
|
114
|
+
destroy() {
|
|
115
|
+
doc.removeEventListener('click', away);
|
|
116
|
+
doc.removeEventListener('keydown', key);
|
|
117
|
+
root.remove();
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
export const KIND_FILTER_CSS = `
|
|
122
|
+
.fx-kinds { position: relative; display: inline-flex; }
|
|
123
|
+
.fx-kinds-button { white-space: nowrap; }
|
|
124
|
+
/* The hidden attribute is display:none from the user agent, which a class setting display outranks. */
|
|
125
|
+
.fx-kinds-panel[hidden] { display: none; }
|
|
126
|
+
.fx-kinds-panel {
|
|
127
|
+
position: absolute; top: calc(100% + 4px); z-index: 40;
|
|
128
|
+
display: grid; gap: 2px; padding: 6px 8px; min-width: 132px;
|
|
129
|
+
background: var(--fx-panel, #14161c);
|
|
130
|
+
border: 1px solid var(--fx-line, #262a35); border-radius: 6px;
|
|
131
|
+
box-shadow: 0 6px 18px rgba(0, 0, 0, .38);
|
|
132
|
+
}
|
|
133
|
+
.fx-kinds-panel:not(.fx-panel-left){ right: 0; }
|
|
134
|
+
.fx-kinds-panel.fx-panel-left { left: 0; }
|
|
135
|
+
.fx-kinds-panel label {
|
|
136
|
+
display: flex; align-items: center; gap: 6px;
|
|
137
|
+
font-size: 11px; color: var(--fx-muted, #8a90a2); cursor: pointer; user-select: none;
|
|
138
|
+
}
|
|
139
|
+
.fx-kinds-panel label:hover { color: var(--fx-label, #e7e9ee); }
|
|
140
|
+
.fx-kinds-panel input { width: 11px; height: 11px; margin: 0; accent-color: var(--fx-accent, #5eead4); }
|
|
141
|
+
.fx-kinds-all {
|
|
142
|
+
padding-bottom: 4px; margin-bottom: 2px;
|
|
143
|
+
border-bottom: 1px solid var(--fx-line, #262a35);
|
|
144
|
+
color: var(--fx-label, #e7e9ee) !important;
|
|
145
|
+
}
|
|
146
|
+
`;
|
|
147
|
+
export const DROPDOWN_FILTER_CSS = `
|
|
148
|
+
.fx-dropdown-btn { background-color: transparent; appearance: none; border: 1px solid var(--line-strong); outline: none; border-radius: .25rem; padding-block: .25rem; padding-inline: .875rem; font-size: .75rem; cursor: pointer }
|
|
149
|
+
.fx-dropdown-btn:hover { border-color: color-mix(in oklab, var(--accent) 50%, transparent); background-color: var(--bg); }
|
|
150
|
+
.fx-dropdown-caret { width: 0;height: 0;border-left: .15rem solid transparent; border-right: .15rem solid transparent; border-top: .15rem solid currentColor; transition: transform 0.2s ease; right: .4rem; top: 50%; color: color-mix(in oklab, var(--muted) 50%, transparent); position: absolute; }
|
|
151
|
+
`;
|
package/dist/menu.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A labelled dropdown of toggles and actions.
|
|
3
|
+
*
|
|
4
|
+
* The graph toolbar had grown to nine bare glyphs. Every one carried a `title`, so the only
|
|
5
|
+
* way to learn what `⇥` did was to hover it and wait, and a reader who was not the author had
|
|
6
|
+
* no chance. This is the same shape as the kind filter, which already solved that for kinds:
|
|
7
|
+
* a named button, and the detail behind it.
|
|
8
|
+
*/
|
|
9
|
+
export type MenuItem = {
|
|
10
|
+
type: 'toggle';
|
|
11
|
+
label: string;
|
|
12
|
+
/** Starting state. Read once. */
|
|
13
|
+
on?: boolean;
|
|
14
|
+
hint?: string;
|
|
15
|
+
onChange: (on: boolean) => void;
|
|
16
|
+
} | {
|
|
17
|
+
type: 'action';
|
|
18
|
+
label: string;
|
|
19
|
+
hint?: string;
|
|
20
|
+
onRun: () => void;
|
|
21
|
+
};
|
|
22
|
+
export interface MenuOptions {
|
|
23
|
+
/** What the button says when nothing is on. */
|
|
24
|
+
label: string;
|
|
25
|
+
items: readonly MenuItem[];
|
|
26
|
+
/** The button's own tooltip. */
|
|
27
|
+
hint?: string;
|
|
28
|
+
menuClass?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface Menu {
|
|
31
|
+
/** Set a toggle from outside, by label, for a host restoring what was last used. */
|
|
32
|
+
set(label: string, on: boolean): void;
|
|
33
|
+
destroy(): void;
|
|
34
|
+
}
|
|
35
|
+
export declare function createMenu(host: HTMLElement, options: MenuOptions): Menu;
|
|
36
|
+
export declare const MENU_CSS = "\n/* The button itself is styled by DROPDOWN_FILTER_CSS, shared with the kind filter. */\n.fx-menu { position: relative; display: inline-flex; }\n.fx-menu-button { white-space: nowrap; position: relative; padding-inline-end: 1.1rem; }\n/* hidden is display:none from the user agent, which a class setting display outranks. */\n.fx-menu-panel[hidden] { display: none; }\n.fx-menu-panel {\n position: absolute; top: calc(100% + 4px); z-index: 40;\n display: grid; gap: 2px; padding: 6px 8px; min-width: 150px;\n background: var(--fx-panel, #14161c);\n border: 1px solid var(--fx-line, #262a35); border-radius: 6px;\n box-shadow: 0 6px 18px rgba(0, 0, 0, .38);\n}\n.fx-menu-panel:not(.fx-panel-left){ right: 0; }\n.fx-menu-panel.fx-panel-left { left: 0; }\n.fx-menu-panel label {\n display: flex; align-items: center; gap: 6px;\n font-size: 11px; color: var(--fx-muted, #8a90a2); cursor: pointer; user-select: none;\n}\n.fx-menu-panel label:hover { color: var(--fx-label, #e7e9ee); }\n.fx-menu-panel input { width: 11px; height: 11px; margin: 0; accent-color: var(--fx-accent, #5eead4); }\n.fx-menu-action {\n text-align: left; padding: 2px 0; border: 0; background: none; cursor: pointer;\n font: inherit; font-size: 11px; color: var(--fx-muted, #8a90a2);\n /* A button does not inherit this, so an action read lowercase beside uppercase toggles. */\n text-transform: inherit; letter-spacing: inherit;\n}\n.fx-menu-action:hover { color: var(--fx-accent, #5eead4); }\n";
|
|
37
|
+
//# sourceMappingURL=menu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menu.d.ts","sourceRoot":"","sources":["../src/menu.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,MAAM,QAAQ,GAChB;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,EAAE,EAAE,OAAO,KAAK,IAAI,CAAC;CACjC,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAEN,MAAM,WAAW,WAAW;IAC1B,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC3B,gCAAgC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,IAAI;IACnB,oFAAoF;IACpF,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IACtC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI,CAmGxE;AAED,eAAO,MAAM,QAAQ,y8CA4BpB,CAAC"}
|
package/dist/menu.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
export function createMenu(host, options) {
|
|
2
|
+
const doc = host.ownerDocument;
|
|
3
|
+
const root = doc.createElement('div');
|
|
4
|
+
root.className = 'fx-menu';
|
|
5
|
+
const button = doc.createElement('button');
|
|
6
|
+
button.type = 'button';
|
|
7
|
+
button.className = 'fx-menu-button fx-dropdown-btn';
|
|
8
|
+
button.setAttribute('aria-haspopup', 'true');
|
|
9
|
+
button.setAttribute('aria-expanded', 'false');
|
|
10
|
+
if (options.hint)
|
|
11
|
+
button.title = options.hint;
|
|
12
|
+
const caret = doc.createElement('div');
|
|
13
|
+
caret.className = 'fx-dropdown-caret';
|
|
14
|
+
const panel = doc.createElement('div');
|
|
15
|
+
panel.className = 'fx-menu-panel';
|
|
16
|
+
if (options.menuClass) {
|
|
17
|
+
panel.classList.add(...options.menuClass.split(/\s+/).filter((c) => c));
|
|
18
|
+
}
|
|
19
|
+
panel.hidden = true;
|
|
20
|
+
const boxes = new Map();
|
|
21
|
+
for (const item of options.items) {
|
|
22
|
+
if (item.type === 'action') {
|
|
23
|
+
const run = doc.createElement('button');
|
|
24
|
+
run.type = 'button';
|
|
25
|
+
run.className = 'fx-menu-action';
|
|
26
|
+
run.textContent = item.label;
|
|
27
|
+
if (item.hint)
|
|
28
|
+
run.title = item.hint;
|
|
29
|
+
run.addEventListener('click', () => {
|
|
30
|
+
close();
|
|
31
|
+
item.onRun();
|
|
32
|
+
});
|
|
33
|
+
panel.append(run);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const box = doc.createElement('input');
|
|
37
|
+
box.type = 'checkbox';
|
|
38
|
+
box.checked = item.on === true;
|
|
39
|
+
const row = doc.createElement('label');
|
|
40
|
+
if (item.hint)
|
|
41
|
+
row.title = item.hint;
|
|
42
|
+
row.append(box, doc.createTextNode(item.label));
|
|
43
|
+
box.addEventListener('change', () => {
|
|
44
|
+
paint();
|
|
45
|
+
item.onChange(box.checked);
|
|
46
|
+
});
|
|
47
|
+
panel.append(row);
|
|
48
|
+
boxes.set(item.label, box);
|
|
49
|
+
}
|
|
50
|
+
root.append(button, panel);
|
|
51
|
+
host.append(root);
|
|
52
|
+
/** The count is what makes a folded menu honest: something is on in here. */
|
|
53
|
+
function paint() {
|
|
54
|
+
let on = 0;
|
|
55
|
+
for (const box of boxes.values())
|
|
56
|
+
if (box.checked)
|
|
57
|
+
on++;
|
|
58
|
+
button.textContent = on ? `${options.label} · ${on}` : options.label;
|
|
59
|
+
// textContent clears it, so the caret goes back after every repaint.
|
|
60
|
+
button.appendChild(caret);
|
|
61
|
+
button.classList.toggle('on', on > 0);
|
|
62
|
+
}
|
|
63
|
+
function close() {
|
|
64
|
+
panel.hidden = true;
|
|
65
|
+
button.setAttribute('aria-expanded', 'false');
|
|
66
|
+
}
|
|
67
|
+
button.addEventListener('click', (event) => {
|
|
68
|
+
event.stopPropagation();
|
|
69
|
+
panel.hidden = !panel.hidden;
|
|
70
|
+
button.setAttribute('aria-expanded', String(!panel.hidden));
|
|
71
|
+
});
|
|
72
|
+
// Clicks inside must not reach the document listener, which closes it.
|
|
73
|
+
panel.addEventListener('click', (event) => event.stopPropagation());
|
|
74
|
+
const away = () => close();
|
|
75
|
+
const key = (event) => {
|
|
76
|
+
if (event.key === 'Escape')
|
|
77
|
+
close();
|
|
78
|
+
};
|
|
79
|
+
doc.addEventListener('click', away);
|
|
80
|
+
doc.addEventListener('keydown', key);
|
|
81
|
+
paint();
|
|
82
|
+
return {
|
|
83
|
+
set(label, on) {
|
|
84
|
+
const box = boxes.get(label);
|
|
85
|
+
if (!box)
|
|
86
|
+
return;
|
|
87
|
+
box.checked = on;
|
|
88
|
+
paint();
|
|
89
|
+
},
|
|
90
|
+
destroy() {
|
|
91
|
+
doc.removeEventListener('click', away);
|
|
92
|
+
doc.removeEventListener('keydown', key);
|
|
93
|
+
root.remove();
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
export const MENU_CSS = `
|
|
98
|
+
/* The button itself is styled by DROPDOWN_FILTER_CSS, shared with the kind filter. */
|
|
99
|
+
.fx-menu { position: relative; display: inline-flex; }
|
|
100
|
+
.fx-menu-button { white-space: nowrap; position: relative; padding-inline-end: 1.1rem; }
|
|
101
|
+
/* hidden is display:none from the user agent, which a class setting display outranks. */
|
|
102
|
+
.fx-menu-panel[hidden] { display: none; }
|
|
103
|
+
.fx-menu-panel {
|
|
104
|
+
position: absolute; top: calc(100% + 4px); z-index: 40;
|
|
105
|
+
display: grid; gap: 2px; padding: 6px 8px; min-width: 150px;
|
|
106
|
+
background: var(--fx-panel, #14161c);
|
|
107
|
+
border: 1px solid var(--fx-line, #262a35); border-radius: 6px;
|
|
108
|
+
box-shadow: 0 6px 18px rgba(0, 0, 0, .38);
|
|
109
|
+
}
|
|
110
|
+
.fx-menu-panel:not(.fx-panel-left){ right: 0; }
|
|
111
|
+
.fx-menu-panel.fx-panel-left { left: 0; }
|
|
112
|
+
.fx-menu-panel label {
|
|
113
|
+
display: flex; align-items: center; gap: 6px;
|
|
114
|
+
font-size: 11px; color: var(--fx-muted, #8a90a2); cursor: pointer; user-select: none;
|
|
115
|
+
}
|
|
116
|
+
.fx-menu-panel label:hover { color: var(--fx-label, #e7e9ee); }
|
|
117
|
+
.fx-menu-panel input { width: 11px; height: 11px; margin: 0; accent-color: var(--fx-accent, #5eead4); }
|
|
118
|
+
.fx-menu-action {
|
|
119
|
+
text-align: left; padding: 2px 0; border: 0; background: none; cursor: pointer;
|
|
120
|
+
font: inherit; font-size: 11px; color: var(--fx-muted, #8a90a2);
|
|
121
|
+
/* A button does not inherit this, so an action read lowercase beside uppercase toggles. */
|
|
122
|
+
text-transform: inherit; letter-spacing: inherit;
|
|
123
|
+
}
|
|
124
|
+
.fx-menu-action:hover { color: var(--fx-accent, #5eead4); }
|
|
125
|
+
`;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { type ReactiveObserver } from '@fluixi/reactive/signal';
|
|
2
|
+
import { type RNode } from './instrument.js';
|
|
3
|
+
import type { ReactiveSourceLocation } from './source.js';
|
|
4
|
+
import { type GraphEvent } from './history.js';
|
|
5
|
+
import { type DomNode } from './dom.js';
|
|
6
|
+
export interface ObservedGraph {
|
|
7
|
+
readonly graph: Map<number, RNode>;
|
|
8
|
+
/** Ids whose value or run count moved since the last call. Drives the pulse. */
|
|
9
|
+
sample(): number[];
|
|
10
|
+
/**
|
|
11
|
+
* The cursor as it stands. A consumer folding in deltas keeps the one it was given and
|
|
12
|
+
* asks for what came after it.
|
|
13
|
+
*/
|
|
14
|
+
readonly revision: number;
|
|
15
|
+
/**
|
|
16
|
+
* Ids that moved after `rev`. Unlike `sample`, asking does not consume anything, so two
|
|
17
|
+
* consumers reading at their own pace each see every change.
|
|
18
|
+
*/
|
|
19
|
+
changedSince(rev: number): number[];
|
|
20
|
+
/** Ids dropped after `rev`. Bounded: a consumer further back than that is told to reload. */
|
|
21
|
+
removedSince(rev: number): number[];
|
|
22
|
+
/** Whether `rev` is old enough that the removal log no longer covers it. */
|
|
23
|
+
outrun(rev: number): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Removals since the last call, draining as it goes.
|
|
26
|
+
*
|
|
27
|
+
* Superseded by `removedSince`, and kept because the hook that calls it can be older
|
|
28
|
+
* than this: a browser extension bundles its own and hands the application's observer
|
|
29
|
+
* to it. Removing the method outright crashed every panel that had not been reloaded.
|
|
30
|
+
*/
|
|
31
|
+
takeRemoved(): number[];
|
|
32
|
+
/** What happened since the last call, in order. Empty when history is off. */
|
|
33
|
+
takeEvents(): GraphEvent[];
|
|
34
|
+
/** Where this node reaches the page, for whatever is still on it. */
|
|
35
|
+
elementsFor(id: number): Element[];
|
|
36
|
+
/** The node driving `element`, or the nearest ancestor that has one. */
|
|
37
|
+
nodeAt(element: Element | null): number | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* What this node rendered, described so it can be shown by a panel that is not in the
|
|
40
|
+
* page. Stops wherever another tag begins, naming it.
|
|
41
|
+
*/
|
|
42
|
+
domFor(id: number): DomNode[];
|
|
43
|
+
/**
|
|
44
|
+
* The elements this tag returned, and nothing else. Unlike `elementsFor` there is no
|
|
45
|
+
* fallback to what the values inside it write to, so two tags can never claim the same
|
|
46
|
+
* element.
|
|
47
|
+
*/
|
|
48
|
+
renderedFor(id: number): Element[];
|
|
49
|
+
/**
|
|
50
|
+
* Write a signal from outside the application. False when the node is not something that
|
|
51
|
+
* can be written. A memo is computed, and setting it would be a lie the next run undoes.
|
|
52
|
+
*/
|
|
53
|
+
setValue(id: number, next: unknown): boolean;
|
|
54
|
+
detach(): void;
|
|
55
|
+
}
|
|
56
|
+
export interface ObserveOptions {
|
|
57
|
+
/**
|
|
58
|
+
* Trimmed off a file name that a dev server serves from its own origin. Defaults to the
|
|
59
|
+
* page's origin, which is what a preview in an iframe wants too.
|
|
60
|
+
*/
|
|
61
|
+
origin?: string;
|
|
62
|
+
/**
|
|
63
|
+
* How to register. Defaults to this copy of the runtime, so pass the application's own
|
|
64
|
+
* `observeReactiveNodes` when watching from outside its module graph, since a second copy
|
|
65
|
+
* of the framework watches a graph nobody is using.
|
|
66
|
+
*/
|
|
67
|
+
observe?: (observer: ReactiveObserver) => () => void;
|
|
68
|
+
/** Events kept for the timeline. 0 for a host that only draws the graph. */
|
|
69
|
+
history?: number;
|
|
70
|
+
/** One stack capture per binding, at creation. Off for a host that never asks. */
|
|
71
|
+
bindingSources?: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Put a stack location back in the author's file. A frame reports the compiled position and
|
|
74
|
+
* knows nothing of the file it was generated from; a host with the source maps closes that.
|
|
75
|
+
* Only stack-derived locations pass through. A compiler mark is already original.
|
|
76
|
+
*/
|
|
77
|
+
mapSource?: (location: ReactiveSourceLocation) => ReactiveSourceLocation | undefined;
|
|
78
|
+
}
|
|
79
|
+
export declare function observeGraph(options?: ObserveOptions): ObservedGraph;
|
|
80
|
+
//# sourceMappingURL=observe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../src/observe.ts"],"names":[],"mappings":"AAUA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAmE,KAAK,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC9G,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAG9D,OAAO,EAA0B,KAAK,OAAO,EAAE,MAAM,UAAU,CAAC;AAmDhE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACnC,gFAAgF;IAChF,MAAM,IAAI,MAAM,EAAE,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACpC,6FAA6F;IAC7F,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACpC,4EAA4E;IAC5E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7B;;;;;;OAMG;IACH,WAAW,IAAI,MAAM,EAAE,CAAC;IACxB,8EAA8E;IAC9E,UAAU,IAAI,UAAU,EAAE,CAAC;IAC3B,qEAAqE;IACrE,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,EAAE,CAAC;IACnC,wEAAwE;IACxE,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC;IACpD;;;OAGG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,EAAE,CAAC;IAC9B;;;;OAIG;IACH,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,EAAE,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IAC7C,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,MAAM,IAAI,CAAC;IACrD,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,sBAAsB,KAAK,sBAAsB,GAAG,SAAS,CAAC;CACtF;AAsED,wBAAgB,YAAY,CAAC,OAAO,GAAE,cAAmB,GAAG,aAAa,CA4tBxE"}
|