@shadow-js/devtools 0.0.0-stage → 1.0.1
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/CHANGELOG.md +21 -0
- package/LICENSE +21 -0
- package/README.md +576 -2
- package/dist/dev/agent.d.ts +239 -0
- package/dist/dev/agent.js +626 -0
- package/dist/dev/agent.js.map +1 -0
- package/dist/dev/backend.d.ts +53 -0
- package/dist/dev/backend.js +53 -0
- package/dist/dev/backend.js.map +1 -0
- package/dist/dev/hook.d.ts +83 -0
- package/dist/dev/hook.js +136 -0
- package/dist/dev/hook.js.map +1 -0
- package/dist/dev/index.d.ts +17 -0
- package/dist/dev/index.js +17 -0
- package/dist/dev/inspection.d.ts +226 -0
- package/dist/dev/inspection.js +263 -0
- package/dist/dev/inspection.js.map +1 -0
- package/dist/dev/inspector.d.ts +331 -0
- package/dist/dev/inspector.js +429 -0
- package/dist/dev/inspector.js.map +1 -0
- package/dist/dev/model.d.ts +418 -0
- package/dist/dev/model.js +559 -0
- package/dist/dev/model.js.map +1 -0
- package/dist/dev/mount.d.ts +207 -0
- package/dist/dev/mount.js +256 -0
- package/dist/dev/mount.js.map +1 -0
- package/dist/dev/overlay.d.ts +102 -0
- package/dist/dev/overlay.js +176 -0
- package/dist/dev/overlay.js.map +1 -0
- package/dist/dev/preview.d.ts +74 -0
- package/dist/dev/preview.js +122 -0
- package/dist/dev/preview.js.map +1 -0
- package/dist/dev/protocol.d.ts +288 -0
- package/dist/dev/protocol.js +109 -0
- package/dist/dev/protocol.js.map +1 -0
- package/dist/dev/ring.d.ts +50 -0
- package/dist/dev/ring.js +94 -0
- package/dist/dev/ring.js.map +1 -0
- package/dist/dev/transport.d.ts +347 -0
- package/dist/dev/transport.js +394 -0
- package/dist/dev/transport.js.map +1 -0
- package/dist/dev/ui/details.js +294 -0
- package/dist/dev/ui/details.js.map +1 -0
- package/dist/dev/ui/inspection-state.d.ts +43 -0
- package/dist/dev/ui/inspection-state.js +62 -0
- package/dist/dev/ui/inspection-state.js.map +1 -0
- package/dist/dev/ui/issues.js +85 -0
- package/dist/dev/ui/issues.js.map +1 -0
- package/dist/dev/ui/panel.d.ts +55 -0
- package/dist/dev/ui/panel.js +160 -0
- package/dist/dev/ui/panel.js.map +1 -0
- package/dist/dev/ui/rows.d.ts +44 -0
- package/dist/dev/ui/rows.js +132 -0
- package/dist/dev/ui/rows.js.map +1 -0
- package/dist/dev/ui/state-tab.js +88 -0
- package/dist/dev/ui/state-tab.js.map +1 -0
- package/dist/dev/ui/state.d.ts +192 -0
- package/dist/dev/ui/state.js +147 -0
- package/dist/dev/ui/state.js.map +1 -0
- package/dist/dev/ui/styles.d.ts +31 -0
- package/dist/dev/ui/styles.js +113 -0
- package/dist/dev/ui/styles.js.map +1 -0
- package/dist/dev/ui/timeline.js +135 -0
- package/dist/dev/ui/timeline.js.map +1 -0
- package/dist/dev/ui/tree.js +186 -0
- package/dist/dev/ui/tree.js.map +1 -0
- package/dist/prod/agent.js +2 -0
- package/dist/prod/agent.js.map +1 -0
- package/dist/prod/backend.js +2 -0
- package/dist/prod/backend.js.map +1 -0
- package/dist/prod/hook.js +2 -0
- package/dist/prod/hook.js.map +1 -0
- package/dist/prod/index.js +1 -0
- package/dist/prod/inspection.js +2 -0
- package/dist/prod/inspection.js.map +1 -0
- package/dist/prod/inspector.js +2 -0
- package/dist/prod/inspector.js.map +1 -0
- package/dist/prod/model.js +2 -0
- package/dist/prod/model.js.map +1 -0
- package/dist/prod/mount.js +2 -0
- package/dist/prod/mount.js.map +1 -0
- package/dist/prod/overlay.js +11 -0
- package/dist/prod/overlay.js.map +1 -0
- package/dist/prod/preview.js +2 -0
- package/dist/prod/preview.js.map +1 -0
- package/dist/prod/protocol.js +2 -0
- package/dist/prod/protocol.js.map +1 -0
- package/dist/prod/ring.js +2 -0
- package/dist/prod/ring.js.map +1 -0
- package/dist/prod/transport.js +2 -0
- package/dist/prod/transport.js.map +1 -0
- package/dist/prod/ui/details.js +2 -0
- package/dist/prod/ui/details.js.map +1 -0
- package/dist/prod/ui/inspection-state.js +2 -0
- package/dist/prod/ui/inspection-state.js.map +1 -0
- package/dist/prod/ui/issues.js +2 -0
- package/dist/prod/ui/issues.js.map +1 -0
- package/dist/prod/ui/panel.js +2 -0
- package/dist/prod/ui/panel.js.map +1 -0
- package/dist/prod/ui/rows.js +2 -0
- package/dist/prod/ui/rows.js.map +1 -0
- package/dist/prod/ui/state-tab.js +2 -0
- package/dist/prod/ui/state-tab.js.map +1 -0
- package/dist/prod/ui/state.js +2 -0
- package/dist/prod/ui/state.js.map +1 -0
- package/dist/prod/ui/styles.js +82 -0
- package/dist/prod/ui/styles.js.map +1 -0
- package/dist/prod/ui/timeline.js +2 -0
- package/dist/prod/ui/timeline.js.map +1 -0
- package/dist/prod/ui/tree.js +2 -0
- package/dist/prod/ui/tree.js.map +1 -0
- package/package.json +69 -4
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { IssuesTab } from "./issues.js";
|
|
2
|
+
import { TABS } from "./state.js";
|
|
3
|
+
import { StateTab } from "./state-tab.js";
|
|
4
|
+
import { TimelineTab } from "./timeline.js";
|
|
5
|
+
import { TreeTab } from "./tree.js";
|
|
6
|
+
import { For, Match, Show, Switch, addEventListener, anchor, createComponent, effect, insert, setAttribute, style, template } from "@shadow-js/web";
|
|
7
|
+
//#region src/ui/panel.tsx
|
|
8
|
+
const _tmpl$ = /*#__PURE__*/ template("<span class=\"badge bad\"></span>");
|
|
9
|
+
const _tmpl$2 = /*#__PURE__*/ template("<button type=\"button\" class=\"tab\" role=\"tab\"></button>");
|
|
10
|
+
const _tmpl$3 = /*#__PURE__*/ template("<section class=\"panel\" role=\"dialog\" aria-label=\"ShadowJS devtools\"><header class=\"header\"><span class=\"title\">ShadowJS devtools</span><span class=\"spacer\"></span><button type=\"button\" class=\"btn\" title=\"Pause or resume recording\"></button><button type=\"button\" class=\"btn\" title=\"Flash components when they update\">Flash</button><button type=\"button\" class=\"btn\" title=\"Forget everything recorded\">Clear</button><button type=\"button\" class=\"btn\" aria-label=\"Close\">×</button></header><div class=\"tabs\" role=\"tablist\"></div><div class=\"body\"></div><footer class=\"footer\"><span> components</span><span> signals</span><span> computations</span><span> runs</span></footer></section>");
|
|
11
|
+
/**
|
|
12
|
+
* The devtools panel: a header with the drag handle and the Pause, Flash, Clear and close controls, the
|
|
13
|
+
* tabs (Components, Timeline, State, Issues), the active view and a footer with counts. It only talks to
|
|
14
|
+
* {@link PanelState}, so it works the same on a local agent and on a remote one.
|
|
15
|
+
*
|
|
16
|
+
* Development tool: `mountDevtools()` renders it in development builds only, and it never ships in
|
|
17
|
+
* production builds.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* import { createAgent, createLocalBackend, createPanelState, Panel } from "@shadow-js/devtools";
|
|
21
|
+
* const backend = createLocalBackend(createAgent());
|
|
22
|
+
* export const Devtools = () => {
|
|
23
|
+
* const state = createPanelState(backend);
|
|
24
|
+
* return <Panel state={state} open={true} x={16} y={16} onMove={() => undefined} onClose={() => undefined} />;
|
|
25
|
+
* };
|
|
26
|
+
* @since 1.0.0
|
|
27
|
+
*/
|
|
28
|
+
const Panel = (props) => {
|
|
29
|
+
let drag = null;
|
|
30
|
+
const begin = (event) => {
|
|
31
|
+
if (event.target instanceof HTMLElement && event.target.closest("button, input, label") !== null) return;
|
|
32
|
+
drag = {
|
|
33
|
+
pointer: event.pointerId,
|
|
34
|
+
x: event.clientX,
|
|
35
|
+
y: event.clientY,
|
|
36
|
+
left: props.x,
|
|
37
|
+
top: props.y
|
|
38
|
+
};
|
|
39
|
+
event.currentTarget.classList.add("dragging");
|
|
40
|
+
if (typeof event.currentTarget.setPointerCapture === "function") event.currentTarget.setPointerCapture(event.pointerId);
|
|
41
|
+
};
|
|
42
|
+
const move = (event) => {
|
|
43
|
+
if (drag === null || event.pointerId !== drag.pointer) return;
|
|
44
|
+
props.onMove(drag.left + event.clientX - drag.x, drag.top + event.clientY - drag.y);
|
|
45
|
+
};
|
|
46
|
+
const end = (event) => {
|
|
47
|
+
if (drag === null || event.pointerId !== drag.pointer) return;
|
|
48
|
+
drag = null;
|
|
49
|
+
event.currentTarget.classList.remove("dragging");
|
|
50
|
+
if (typeof event.currentTarget.releasePointerCapture === "function" && event.currentTarget.hasPointerCapture?.(event.pointerId) === true) event.currentTarget.releasePointerCapture(event.pointerId);
|
|
51
|
+
};
|
|
52
|
+
const clear = () => {
|
|
53
|
+
props.state.backend.request({ type: "clear" }).then(() => props.state.refresh());
|
|
54
|
+
};
|
|
55
|
+
{
|
|
56
|
+
const _el$ = _tmpl$3(), _el$2 = _el$.firstChild, _el$6 = _el$2.firstChild.nextSibling.nextSibling, _el$7 = _el$6.nextSibling, _el$8 = _el$7.nextSibling, _el$9 = _el$8.nextSibling, _el$3 = _el$2.nextSibling, _el$4 = _el$3.nextSibling, _el$10 = _el$4.nextSibling.firstChild, _el$14 = _el$10.firstChild, _el$11 = _el$10.nextSibling, _el$15 = _el$11.firstChild, _el$12 = _el$11.nextSibling, _el$16 = _el$12.firstChild, _el$13 = _el$12.nextSibling, _el$17 = _el$13.firstChild;
|
|
57
|
+
effect(() => {
|
|
58
|
+
_el$.hidden = !props.open;
|
|
59
|
+
});
|
|
60
|
+
effect(() => ({
|
|
61
|
+
left: `${props.x}px`,
|
|
62
|
+
top: `${props.y}px`
|
|
63
|
+
}), (_v$, _p$) => {
|
|
64
|
+
style(_el$, _v$, _p$);
|
|
65
|
+
});
|
|
66
|
+
addEventListener(_el$2, "pointerdown", begin);
|
|
67
|
+
addEventListener(_el$2, "pointermove", move);
|
|
68
|
+
addEventListener(_el$2, "pointerup", end);
|
|
69
|
+
addEventListener(_el$2, "pointercancel", end);
|
|
70
|
+
effect(() => {
|
|
71
|
+
setAttribute(_el$6, "aria-pressed", props.state.paused());
|
|
72
|
+
});
|
|
73
|
+
addEventListener(_el$6, "click", () => props.state.setPaused(!props.state.paused()));
|
|
74
|
+
insert(_el$6, () => props.state.paused() ? "Resume" : "Pause");
|
|
75
|
+
effect(() => {
|
|
76
|
+
setAttribute(_el$7, "aria-pressed", props.state.flash());
|
|
77
|
+
});
|
|
78
|
+
addEventListener(_el$7, "click", () => props.state.setFlash(!props.state.flash()));
|
|
79
|
+
addEventListener(_el$8, "click", clear);
|
|
80
|
+
addEventListener(_el$9, "click", () => props.onClose());
|
|
81
|
+
insert(_el$3, createComponent(For, {
|
|
82
|
+
each: TABS,
|
|
83
|
+
children: (tab) => {
|
|
84
|
+
const _el$ = _tmpl$2(), _el$2 = anchor(_el$, null);
|
|
85
|
+
effect(() => {
|
|
86
|
+
setAttribute(_el$, "aria-selected", props.state.tab() === tab.id);
|
|
87
|
+
});
|
|
88
|
+
effect(() => {
|
|
89
|
+
setAttribute(_el$, "data-tab", tab.id);
|
|
90
|
+
});
|
|
91
|
+
addEventListener(_el$, "click", () => props.state.setTab(tab.id));
|
|
92
|
+
insert(_el$, () => tab.label, _el$2);
|
|
93
|
+
insert(_el$, createComponent(Show, {
|
|
94
|
+
get when() {
|
|
95
|
+
return tab.id === "issues" && props.state.snapshot().counts.errors + props.state.snapshot().counts.hydration > 0;
|
|
96
|
+
},
|
|
97
|
+
get children() {
|
|
98
|
+
const _el$ = _tmpl$();
|
|
99
|
+
insert(_el$, () => props.state.snapshot().counts.errors + props.state.snapshot().counts.hydration);
|
|
100
|
+
return _el$;
|
|
101
|
+
}
|
|
102
|
+
}, "Show"));
|
|
103
|
+
return _el$;
|
|
104
|
+
}
|
|
105
|
+
}, "For"));
|
|
106
|
+
insert(_el$4, createComponent(Switch, { get children() {
|
|
107
|
+
return [
|
|
108
|
+
createComponent(Match, {
|
|
109
|
+
get when() {
|
|
110
|
+
return props.state.tab() === "tree";
|
|
111
|
+
},
|
|
112
|
+
get children() {
|
|
113
|
+
return createComponent(TreeTab, { get state() {
|
|
114
|
+
return props.state;
|
|
115
|
+
} }, "TreeTab");
|
|
116
|
+
}
|
|
117
|
+
}, "Match"),
|
|
118
|
+
createComponent(Match, {
|
|
119
|
+
get when() {
|
|
120
|
+
return props.state.tab() === "timeline";
|
|
121
|
+
},
|
|
122
|
+
get children() {
|
|
123
|
+
return createComponent(TimelineTab, { get state() {
|
|
124
|
+
return props.state;
|
|
125
|
+
} }, "TimelineTab");
|
|
126
|
+
}
|
|
127
|
+
}, "Match"),
|
|
128
|
+
createComponent(Match, {
|
|
129
|
+
get when() {
|
|
130
|
+
return props.state.tab() === "state";
|
|
131
|
+
},
|
|
132
|
+
get children() {
|
|
133
|
+
return createComponent(StateTab, { get state() {
|
|
134
|
+
return props.state;
|
|
135
|
+
} }, "StateTab");
|
|
136
|
+
}
|
|
137
|
+
}, "Match"),
|
|
138
|
+
createComponent(Match, {
|
|
139
|
+
get when() {
|
|
140
|
+
return props.state.tab() === "issues";
|
|
141
|
+
},
|
|
142
|
+
get children() {
|
|
143
|
+
return createComponent(IssuesTab, { get state() {
|
|
144
|
+
return props.state;
|
|
145
|
+
} }, "IssuesTab");
|
|
146
|
+
}
|
|
147
|
+
}, "Match")
|
|
148
|
+
];
|
|
149
|
+
} }, "Switch"));
|
|
150
|
+
insert(_el$10, () => props.state.snapshot().counts.components, _el$14);
|
|
151
|
+
insert(_el$11, () => props.state.snapshot().counts.signals, _el$15);
|
|
152
|
+
insert(_el$12, () => props.state.snapshot().counts.memos + props.state.snapshot().counts.effects, _el$16);
|
|
153
|
+
insert(_el$13, () => props.state.snapshot().counts.runs, _el$17);
|
|
154
|
+
return _el$;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
//#endregion
|
|
158
|
+
export { Panel };
|
|
159
|
+
|
|
160
|
+
//# sourceMappingURL=panel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panel.js","names":["_$createComponent","_$anchor"],"sources":["../../../src/ui/panel.tsx"],"sourcesContent":["import { For, Match, Show, Switch } from \"@shadow-js/web\";\nimport type { Component } from \"@shadow-js/web/jsx-runtime\";\nimport { IssuesTab } from \"./issues\";\nimport { type PanelState, TABS } from \"./state\";\nimport { StateTab } from \"./state-tab\";\nimport { TimelineTab } from \"./timeline\";\nimport { TreeTab } from \"./tree\";\n\n/**\n * Props of {@link Panel}.\n *\n * @since 1.0.0\n */\nexport interface PanelProps {\n /**\n * The panel's state, from {@link createPanelState}.\n */\n state: PanelState;\n /**\n * Whether the panel is shown. A closed panel keeps its state and is hidden.\n */\n open: boolean;\n /**\n * Left edge of the panel in pixels.\n */\n x: number;\n /**\n * Top edge of the panel in pixels.\n */\n y: number;\n /**\n * Called while the header is dragged, with the new position in pixels. The panel does not move itself;\n * the owner sets `x` and `y`.\n */\n onMove(x: number, y: number): void;\n /**\n * Called when the close button is pressed.\n */\n onClose(): void;\n}\n\ninterface DragStart {\n pointer: number;\n x: number;\n y: number;\n left: number;\n top: number;\n}\n\n/**\n * The devtools panel: a header with the drag handle and the Pause, Flash, Clear and close controls, the\n * tabs (Components, Timeline, State, Issues), the active view and a footer with counts. It only talks to\n * {@link PanelState}, so it works the same on a local agent and on a remote one.\n *\n * Development tool: `mountDevtools()` renders it in development builds only, and it never ships in\n * production builds.\n *\n * @example\n * import { createAgent, createLocalBackend, createPanelState, Panel } from \"@shadow-js/devtools\";\n * const backend = createLocalBackend(createAgent());\n * export const Devtools = () => {\n * const state = createPanelState(backend);\n * return <Panel state={state} open={true} x={16} y={16} onMove={() => undefined} onClose={() => undefined} />;\n * };\n * @since 1.0.0\n */\nexport const Panel: Component<PanelProps> = (props) => {\n let drag: DragStart | null = null;\n\n const begin = (event: PointerEvent & { currentTarget: HTMLElement }): void => {\n if (\n event.target instanceof HTMLElement &&\n event.target.closest(\"button, input, label\") !== null\n )\n return;\n drag = {\n pointer: event.pointerId,\n x: event.clientX,\n y: event.clientY,\n left: props.x,\n top: props.y,\n };\n event.currentTarget.classList.add(\"dragging\");\n if (typeof event.currentTarget.setPointerCapture === \"function\") {\n event.currentTarget.setPointerCapture(event.pointerId);\n }\n };\n const move = (event: PointerEvent): void => {\n if (drag === null || event.pointerId !== drag.pointer) return;\n props.onMove(drag.left + event.clientX - drag.x, drag.top + event.clientY - drag.y);\n };\n const end = (event: PointerEvent & { currentTarget: HTMLElement }): void => {\n if (drag === null || event.pointerId !== drag.pointer) return;\n drag = null;\n event.currentTarget.classList.remove(\"dragging\");\n if (\n typeof event.currentTarget.releasePointerCapture === \"function\" &&\n event.currentTarget.hasPointerCapture?.(event.pointerId) === true\n ) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n };\n\n const clear = (): void => {\n void props.state.backend.request({ type: \"clear\" }).then(() => props.state.refresh());\n };\n\n return (\n <section\n class=\"panel\"\n role=\"dialog\"\n aria-label=\"ShadowJS devtools\"\n hidden={!props.open}\n style={{ left: `${props.x}px`, top: `${props.y}px` }}\n >\n <header\n class=\"header\"\n on:pointerdown={begin}\n on:pointermove={move}\n on:pointerup={end}\n on:pointercancel={end}\n >\n <span class=\"title\">ShadowJS devtools</span>\n <span class=\"spacer\" />\n <button\n type=\"button\"\n class=\"btn\"\n aria-pressed={props.state.paused()}\n title=\"Pause or resume recording\"\n on:click={() => props.state.setPaused(!props.state.paused())}\n >\n {props.state.paused() ? \"Resume\" : \"Pause\"}\n </button>\n <button\n type=\"button\"\n class=\"btn\"\n aria-pressed={props.state.flash()}\n title=\"Flash components when they update\"\n on:click={() => props.state.setFlash(!props.state.flash())}\n >\n Flash\n </button>\n <button type=\"button\" class=\"btn\" title=\"Forget everything recorded\" on:click={clear}>\n Clear\n </button>\n <button type=\"button\" class=\"btn\" aria-label=\"Close\" on:click={() => props.onClose()}>\n ×\n </button>\n </header>\n <div class=\"tabs\" role=\"tablist\">\n <For each={TABS}>\n {(tab) => (\n <button\n type=\"button\"\n class=\"tab\"\n role=\"tab\"\n aria-selected={props.state.tab() === tab.id}\n data-tab={tab.id}\n on:click={() => props.state.setTab(tab.id)}\n >\n {tab.label}\n <Show\n when={\n tab.id === \"issues\" &&\n props.state.snapshot().counts.errors + props.state.snapshot().counts.hydration > 0\n }\n >\n <span class=\"badge bad\">\n {props.state.snapshot().counts.errors + props.state.snapshot().counts.hydration}\n </span>\n </Show>\n </button>\n )}\n </For>\n </div>\n <div class=\"body\">\n <Switch>\n <Match when={props.state.tab() === \"tree\"}>\n <TreeTab state={props.state} />\n </Match>\n <Match when={props.state.tab() === \"timeline\"}>\n <TimelineTab state={props.state} />\n </Match>\n <Match when={props.state.tab() === \"state\"}>\n <StateTab state={props.state} />\n </Match>\n <Match when={props.state.tab() === \"issues\"}>\n <IssuesTab state={props.state} />\n </Match>\n </Switch>\n </div>\n <footer class=\"footer\">\n <span>{props.state.snapshot().counts.components} components</span>\n <span>{props.state.snapshot().counts.signals} signals</span>\n <span>\n {props.state.snapshot().counts.memos + props.state.snapshot().counts.effects} computations\n </span>\n <span>{props.state.snapshot().counts.runs} runs</span>\n </footer>\n </section>\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { NodeType } from "../model.js";
|
|
2
|
+
//#region src/ui/rows.d.ts
|
|
3
|
+
/** One line of the tree view. @since 1.0.0 */
|
|
4
|
+
export interface TreeRow {
|
|
5
|
+
/**
|
|
6
|
+
* Id of the node.
|
|
7
|
+
*/
|
|
8
|
+
id: number;
|
|
9
|
+
/**
|
|
10
|
+
* Nesting level of the row: `0` for a root. With components only, a row sits one level below its
|
|
11
|
+
* nearest shown ancestor.
|
|
12
|
+
*/
|
|
13
|
+
depth: number;
|
|
14
|
+
/**
|
|
15
|
+
* The kind of the node.
|
|
16
|
+
*/
|
|
17
|
+
type: NodeType;
|
|
18
|
+
/**
|
|
19
|
+
* True for a component node.
|
|
20
|
+
*/
|
|
21
|
+
isComponent: boolean;
|
|
22
|
+
/** Display name: `<Counter>`, `count`, `effect#12`. */
|
|
23
|
+
label: string;
|
|
24
|
+
/**
|
|
25
|
+
* Secondary text: a signal's value, a resource's state, or the run count of a memo or effect.
|
|
26
|
+
*/
|
|
27
|
+
detail: string;
|
|
28
|
+
/**
|
|
29
|
+
* True when the node has children in the list. While a filter is set, only matching children count.
|
|
30
|
+
*/
|
|
31
|
+
hasChildren: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* True when the node's children are hidden. Always false while a filter is set.
|
|
34
|
+
*/
|
|
35
|
+
collapsed: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Re-runs after the first, summed over the node and everything below it in the owners tree.
|
|
38
|
+
*/
|
|
39
|
+
updates: number;
|
|
40
|
+
/** Id of the component that owns the node ({@link NO_ID} for none). */
|
|
41
|
+
component: number;
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
//# sourceMappingURL=rows.d.ts.map
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import "../protocol.js";
|
|
2
|
+
import { nodeLabel } from "../inspector.js";
|
|
3
|
+
//#region src/ui/rows.ts
|
|
4
|
+
function labelOf(node) {
|
|
5
|
+
if (node.isComponent) return `<${node.name ?? `component#${node.id}`}>`;
|
|
6
|
+
return nodeLabel(node);
|
|
7
|
+
}
|
|
8
|
+
function detailOf(node) {
|
|
9
|
+
switch (node.type) {
|
|
10
|
+
case "signal": return node.preview;
|
|
11
|
+
case "resource": return node.state;
|
|
12
|
+
case "memo":
|
|
13
|
+
case "effect": return node.runs === 0 ? "" : `${node.runs} run${node.runs === 1 ? "" : "s"}`;
|
|
14
|
+
default: return "";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Flattens the owners tree into the rows the tree view shows: depth first, children in creation order,
|
|
19
|
+
* honoring the collapse state, the text filter and the components-only switch. Iterative, so a deep or
|
|
20
|
+
* large tree does not overflow the call stack.
|
|
21
|
+
*
|
|
22
|
+
* Internal to the panel: the package index does not export this function.
|
|
23
|
+
*
|
|
24
|
+
* @param snapshot A graph snapshot.
|
|
25
|
+
* @param options Filter, switches and the row limit.
|
|
26
|
+
* @returns The rows and how many matches were cut.
|
|
27
|
+
* @internal
|
|
28
|
+
*/
|
|
29
|
+
function buildRows(snapshot, options) {
|
|
30
|
+
const byId = /* @__PURE__ */ new Map();
|
|
31
|
+
for (const node of snapshot.nodes) byId.set(node.id, node);
|
|
32
|
+
const filter = options.filter.trim().toLowerCase();
|
|
33
|
+
const filtering = filter !== "";
|
|
34
|
+
const rolled = /* @__PURE__ */ new Map();
|
|
35
|
+
for (const node of snapshot.nodes) {
|
|
36
|
+
if (node.updates === 0) continue;
|
|
37
|
+
let current = node;
|
|
38
|
+
let guard = 0;
|
|
39
|
+
while (current !== void 0 && guard < snapshot.nodes.length + 1) {
|
|
40
|
+
rolled.set(current.id, (rolled.get(current.id) ?? 0) + node.updates);
|
|
41
|
+
current = current.parent === 0 ? void 0 : byId.get(current.parent);
|
|
42
|
+
guard += 1;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
let included = null;
|
|
46
|
+
if (filtering) {
|
|
47
|
+
const matches = /* @__PURE__ */ new Set();
|
|
48
|
+
for (const node of snapshot.nodes) {
|
|
49
|
+
if (!`${labelOf(node)} ${node.type} ${node.preview} ${node.state}`.toLowerCase().includes(filter)) continue;
|
|
50
|
+
let current = node;
|
|
51
|
+
while (current !== void 0 && !matches.has(current.id)) {
|
|
52
|
+
matches.add(current.id);
|
|
53
|
+
current = current.parent === 0 ? void 0 : byId.get(current.parent);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
included = matches;
|
|
57
|
+
}
|
|
58
|
+
const limit = options.limit ?? 2e3;
|
|
59
|
+
const rows = [];
|
|
60
|
+
let hidden = 0;
|
|
61
|
+
const stack = [];
|
|
62
|
+
for (let i = snapshot.roots.length - 1; i >= 0; i -= 1) {
|
|
63
|
+
const id = snapshot.roots[i];
|
|
64
|
+
if (id !== void 0) stack.push({
|
|
65
|
+
id,
|
|
66
|
+
depth: 0
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
while (stack.length > 0) {
|
|
70
|
+
const entry = stack.pop();
|
|
71
|
+
if (entry === void 0) break;
|
|
72
|
+
const node = byId.get(entry.id);
|
|
73
|
+
if (node === void 0) continue;
|
|
74
|
+
if (included !== null && !included.has(node.id)) continue;
|
|
75
|
+
const shown = !options.componentsOnly || node.isComponent;
|
|
76
|
+
const children = node.children.filter((id) => included === null || included.has(id));
|
|
77
|
+
const collapsed = !filtering && options.collapsed.has(node.id);
|
|
78
|
+
if (shown) {
|
|
79
|
+
if (rows.length < limit) rows.push({
|
|
80
|
+
id: node.id,
|
|
81
|
+
depth: entry.depth,
|
|
82
|
+
type: node.type,
|
|
83
|
+
isComponent: node.isComponent,
|
|
84
|
+
label: labelOf(node),
|
|
85
|
+
detail: detailOf(node),
|
|
86
|
+
hasChildren: children.length > 0,
|
|
87
|
+
collapsed,
|
|
88
|
+
updates: rolled.get(node.id) ?? 0,
|
|
89
|
+
component: node.component
|
|
90
|
+
});
|
|
91
|
+
else hidden += 1;
|
|
92
|
+
}
|
|
93
|
+
if (collapsed) continue;
|
|
94
|
+
const childDepth = shown ? entry.depth + 1 : entry.depth;
|
|
95
|
+
for (let i = children.length - 1; i >= 0; i -= 1) {
|
|
96
|
+
const child = children[i];
|
|
97
|
+
if (child !== void 0) stack.push({
|
|
98
|
+
id: child,
|
|
99
|
+
depth: childDepth
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
rows,
|
|
105
|
+
hidden
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* One or two letters that name a row's kind in the tree: `C` for a component, `O` owner, `S` signal,
|
|
110
|
+
* `M` memo, `E` effect, `R` resource and `ST` store.
|
|
111
|
+
*
|
|
112
|
+
* Internal to the panel: the package index does not export this function.
|
|
113
|
+
*
|
|
114
|
+
* @param row The row.
|
|
115
|
+
* @returns The letters.
|
|
116
|
+
* @internal
|
|
117
|
+
*/
|
|
118
|
+
function kindLetter(row) {
|
|
119
|
+
if (row.isComponent) return "C";
|
|
120
|
+
switch (row.type) {
|
|
121
|
+
case "owner": return "O";
|
|
122
|
+
case "signal": return "S";
|
|
123
|
+
case "memo": return "M";
|
|
124
|
+
case "effect": return "E";
|
|
125
|
+
case "resource": return "R";
|
|
126
|
+
case "store": return "ST";
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//#endregion
|
|
130
|
+
export { buildRows, kindLetter };
|
|
131
|
+
|
|
132
|
+
//# sourceMappingURL=rows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rows.js","names":[],"sources":["../../../src/ui/rows.ts"],"sourcesContent":["import { type GraphSnapshot, nodeLabel, type SnapshotNode } from \"../inspector\";\nimport type { NodeType } from \"../model\";\nimport { NO_ID } from \"../protocol\";\n\n/** One line of the tree view. @since 1.0.0 */\nexport interface TreeRow {\n /**\n * Id of the node.\n */\n id: number;\n /**\n * Nesting level of the row: `0` for a root. With components only, a row sits one level below its\n * nearest shown ancestor.\n */\n depth: number;\n /**\n * The kind of the node.\n */\n type: NodeType;\n /**\n * True for a component node.\n */\n isComponent: boolean;\n /** Display name: `<Counter>`, `count`, `effect#12`. */\n label: string;\n /**\n * Secondary text: a signal's value, a resource's state, or the run count of a memo or effect.\n */\n detail: string;\n /**\n * True when the node has children in the list. While a filter is set, only matching children count.\n */\n hasChildren: boolean;\n /**\n * True when the node's children are hidden. Always false while a filter is set.\n */\n collapsed: boolean;\n /**\n * Re-runs after the first, summed over the node and everything below it in the owners tree.\n */\n updates: number;\n /** Id of the component that owns the node ({@link NO_ID} for none). */\n component: number;\n}\n\n/** What to show in the tree. @since 1.0.0 */\nexport interface RowOptions {\n /** Case-insensitive text matched against names, kinds and values. Matches are shown with their ancestors. */\n filter: string;\n /** Show only components (their descendants are attached to the nearest shown ancestor). */\n componentsOnly: boolean;\n /**\n * Ids the user collapsed. Everything else is expanded. Ignored while `filter` is set.\n */\n collapsed: ReadonlySet<number>;\n /**\n * Most rows returned.\n *\n * @default 2000\n */\n limit?: number;\n}\n\n/**\n * Result of {@link buildRows}.\n *\n * @since 1.0.0\n */\nexport interface RowsResult {\n /**\n * The visible rows, depth first.\n */\n rows: TreeRow[];\n /** Rows that matched but were cut by `limit`. */\n hidden: number;\n}\n\nfunction labelOf(node: SnapshotNode): string {\n if (node.isComponent) return `<${node.name ?? `component#${node.id}`}>`;\n return nodeLabel(node);\n}\n\nfunction detailOf(node: SnapshotNode): string {\n switch (node.type) {\n case \"signal\":\n return node.preview;\n case \"resource\":\n return node.state;\n case \"memo\":\n case \"effect\":\n return node.runs === 0 ? \"\" : `${node.runs} run${node.runs === 1 ? \"\" : \"s\"}`;\n default:\n return \"\";\n }\n}\n\n/**\n * Flattens the owners tree into the rows the tree view shows: depth first, children in creation order,\n * honoring the collapse state, the text filter and the components-only switch. Iterative, so a deep or\n * large tree does not overflow the call stack.\n *\n * Internal to the panel: the package index does not export this function.\n *\n * @param snapshot A graph snapshot.\n * @param options Filter, switches and the row limit.\n * @returns The rows and how many matches were cut.\n * @internal\n */\nexport function buildRows(snapshot: GraphSnapshot, options: RowOptions): RowsResult {\n const byId = new Map<number, SnapshotNode>();\n for (const node of snapshot.nodes) byId.set(node.id, node);\n const filter = options.filter.trim().toLowerCase();\n const filtering = filter !== \"\";\n\n // Updates roll up: a component shows the re-runs of everything below it.\n const rolled = new Map<number, number>();\n for (const node of snapshot.nodes) {\n if (node.updates === 0) continue;\n let current: SnapshotNode | undefined = node;\n let guard = 0;\n while (current !== undefined && guard < snapshot.nodes.length + 1) {\n rolled.set(current.id, (rolled.get(current.id) ?? 0) + node.updates);\n current = current.parent === NO_ID ? undefined : byId.get(current.parent);\n guard += 1;\n }\n }\n\n // With a filter, only matches and their ancestors take part.\n let included: Set<number> | null = null;\n if (filtering) {\n const matches = new Set<number>();\n for (const node of snapshot.nodes) {\n const haystack = `${labelOf(node)} ${node.type} ${node.preview} ${node.state}`.toLowerCase();\n if (!haystack.includes(filter)) continue;\n let current: SnapshotNode | undefined = node;\n while (current !== undefined && !matches.has(current.id)) {\n matches.add(current.id);\n current = current.parent === NO_ID ? undefined : byId.get(current.parent);\n }\n }\n included = matches;\n }\n\n const limit = options.limit ?? 2000;\n const rows: TreeRow[] = [];\n let hidden = 0;\n const stack: Array<{ id: number; depth: number }> = [];\n for (let i = snapshot.roots.length - 1; i >= 0; i -= 1) {\n const id = snapshot.roots[i];\n if (id !== undefined) stack.push({ id, depth: 0 });\n }\n while (stack.length > 0) {\n const entry = stack.pop();\n if (entry === undefined) break;\n const node = byId.get(entry.id);\n if (node === undefined) continue;\n if (included !== null && !included.has(node.id)) continue;\n const shown = !options.componentsOnly || node.isComponent;\n const children = node.children.filter((id) => included === null || included.has(id));\n const collapsed = !filtering && options.collapsed.has(node.id);\n if (shown) {\n if (rows.length < limit) {\n rows.push({\n id: node.id,\n depth: entry.depth,\n type: node.type,\n isComponent: node.isComponent,\n label: labelOf(node),\n detail: detailOf(node),\n hasChildren: children.length > 0,\n collapsed,\n updates: rolled.get(node.id) ?? 0,\n component: node.component,\n });\n } else {\n hidden += 1;\n }\n }\n if (collapsed) continue;\n const childDepth = shown ? entry.depth + 1 : entry.depth;\n for (let i = children.length - 1; i >= 0; i -= 1) {\n const child = children[i];\n if (child !== undefined) stack.push({ id: child, depth: childDepth });\n }\n }\n return { rows, hidden };\n}\n\n/**\n * One or two letters that name a row's kind in the tree: `C` for a component, `O` owner, `S` signal,\n * `M` memo, `E` effect, `R` resource and `ST` store.\n *\n * Internal to the panel: the package index does not export this function.\n *\n * @param row The row.\n * @returns The letters.\n * @internal\n */\nexport function kindLetter(row: { type: NodeType; isComponent: boolean }): string {\n if (row.isComponent) return \"C\";\n switch (row.type) {\n case \"owner\":\n return \"O\";\n case \"signal\":\n return \"S\";\n case \"memo\":\n return \"M\";\n case \"effect\":\n return \"E\";\n case \"resource\":\n return \"R\";\n case \"store\":\n return \"ST\";\n }\n}\n"],"mappings":";;;AA6EA,SAAS,QAAQ,MAA4B;CAC3C,IAAI,KAAK,aAAa,OAAO,IAAI,KAAK,QAAQ,aAAa,KAAK,KAAK;CACrE,OAAO,UAAU,IAAI;AACvB;AAEA,SAAS,SAAS,MAA4B;CAC5C,QAAQ,KAAK,MAAb;EACE,KAAK,UACH,OAAO,KAAK;EACd,KAAK,YACH,OAAO,KAAK;EACd,KAAK;EACL,KAAK,UACH,OAAO,KAAK,SAAS,IAAI,KAAK,GAAG,KAAK,KAAK,MAAM,KAAK,SAAS,IAAI,KAAK;EAC1E,SACE,OAAO;CACX;AACF;;;;;;;;;;;;;AAcA,SAAgB,UAAU,UAAyB,SAAiC;CAClF,MAAM,uBAAO,IAAI,IAA0B;CAC3C,KAAK,MAAM,QAAQ,SAAS,OAAO,KAAK,IAAI,KAAK,IAAI,IAAI;CACzD,MAAM,SAAS,QAAQ,OAAO,KAAK,CAAC,CAAC,YAAY;CACjD,MAAM,YAAY,WAAW;CAG7B,MAAM,yBAAS,IAAI,IAAoB;CACvC,KAAK,MAAM,QAAQ,SAAS,OAAO;EACjC,IAAI,KAAK,YAAY,GAAG;EACxB,IAAI,UAAoC;EACxC,IAAI,QAAQ;EACZ,OAAO,YAAY,KAAA,KAAa,QAAQ,SAAS,MAAM,SAAS,GAAG;GACjE,OAAO,IAAI,QAAQ,KAAK,OAAO,IAAI,QAAQ,EAAE,KAAK,KAAK,KAAK,OAAO;GACnE,UAAU,QAAQ,WAAA,IAAmB,KAAA,IAAY,KAAK,IAAI,QAAQ,MAAM;GACxE,SAAS;EACX;CACF;CAGA,IAAI,WAA+B;CACnC,IAAI,WAAW;EACb,MAAM,0BAAU,IAAI,IAAY;EAChC,KAAK,MAAM,QAAQ,SAAS,OAAO;GAEjC,IAAI,CADa,GAAG,QAAQ,IAAI,EAAE,GAAG,KAAK,KAAK,GAAG,KAAK,QAAQ,GAAG,KAAK,QAAQ,YACnE,CAAC,CAAC,SAAS,MAAM,GAAG;GAChC,IAAI,UAAoC;GACxC,OAAO,YAAY,KAAA,KAAa,CAAC,QAAQ,IAAI,QAAQ,EAAE,GAAG;IACxD,QAAQ,IAAI,QAAQ,EAAE;IACtB,UAAU,QAAQ,WAAA,IAAmB,KAAA,IAAY,KAAK,IAAI,QAAQ,MAAM;GAC1E;EACF;EACA,WAAW;CACb;CAEA,MAAM,QAAQ,QAAQ,SAAS;CAC/B,MAAM,OAAkB,CAAC;CACzB,IAAI,SAAS;CACb,MAAM,QAA8C,CAAC;CACrD,KAAK,IAAI,IAAI,SAAS,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG;EACtD,MAAM,KAAK,SAAS,MAAM;EAC1B,IAAI,OAAO,KAAA,GAAW,MAAM,KAAK;GAAE;GAAI,OAAO;EAAE,CAAC;CACnD;CACA,OAAO,MAAM,SAAS,GAAG;EACvB,MAAM,QAAQ,MAAM,IAAI;EACxB,IAAI,UAAU,KAAA,GAAW;EACzB,MAAM,OAAO,KAAK,IAAI,MAAM,EAAE;EAC9B,IAAI,SAAS,KAAA,GAAW;EACxB,IAAI,aAAa,QAAQ,CAAC,SAAS,IAAI,KAAK,EAAE,GAAG;EACjD,MAAM,QAAQ,CAAC,QAAQ,kBAAkB,KAAK;EAC9C,MAAM,WAAW,KAAK,SAAS,QAAQ,OAAO,aAAa,QAAQ,SAAS,IAAI,EAAE,CAAC;EACnF,MAAM,YAAY,CAAC,aAAa,QAAQ,UAAU,IAAI,KAAK,EAAE;EAC7D,IAAI,OAAO;GACT,IAAI,KAAK,SAAS,OAChB,KAAK,KAAK;IACR,IAAI,KAAK;IACT,OAAO,MAAM;IACb,MAAM,KAAK;IACX,aAAa,KAAK;IAClB,OAAO,QAAQ,IAAI;IACnB,QAAQ,SAAS,IAAI;IACrB,aAAa,SAAS,SAAS;IAC/B;IACA,SAAS,OAAO,IAAI,KAAK,EAAE,KAAK;IAChC,WAAW,KAAK;GAClB,CAAC;QAED,UAAU;EAEd;EACA,IAAI,WAAW;EACf,MAAM,aAAa,QAAQ,MAAM,QAAQ,IAAI,MAAM;EACnD,KAAK,IAAI,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG;GAChD,MAAM,QAAQ,SAAS;GACvB,IAAI,UAAU,KAAA,GAAW,MAAM,KAAK;IAAE,IAAI;IAAO,OAAO;GAAW,CAAC;EACtE;CACF;CACA,OAAO;EAAE;EAAM;CAAO;AACxB;;;;;;;;;;;AAYA,SAAgB,WAAW,KAAuD;CAChF,IAAI,IAAI,aAAa,OAAO;CAC5B,QAAQ,IAAI,MAAZ;EACE,KAAK,SACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,YACH,OAAO;EACT,KAAK,SACH,OAAO;CACX;AACF"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Details } from "./details.js";
|
|
2
|
+
import { For, Show, addEventListener, className, createComponent, effect, insert, setAttribute, template } from "@shadow-js/web";
|
|
3
|
+
//#region src/ui/state-tab.tsx
|
|
4
|
+
const _tmpl$ = /*#__PURE__*/ template("<div class=\"empty\">No signals or stores yet.</div>");
|
|
5
|
+
const _tmpl$2 = /*#__PURE__*/ template("<span class=\"updates\" title=\"Writes\">×</span>");
|
|
6
|
+
const _tmpl$3 = /*#__PURE__*/ template("<div class=\"row\" role=\"option\" tabindex=\"0\"><span></span><span class=\"name\"></span><span class=\"value\"></span></div>");
|
|
7
|
+
const _tmpl$4 = /*#__PURE__*/ template("<div class=\"split\"><div class=\"list\" role=\"listbox\" aria-label=\"State\"></div></div>");
|
|
8
|
+
/**
|
|
9
|
+
* The State tab. Props: `state` is the panel's {@link PanelState}. It lists every signal, store and
|
|
10
|
+
* resource with its current value (and its write count when it is above zero). Selecting a row (click, Enter or Space) shows its
|
|
11
|
+
* details; for signals and stores the details include a value editor, where a change is applied like any
|
|
12
|
+
* other write.
|
|
13
|
+
*
|
|
14
|
+
* Internal to the panel: the package index does not export this component. Used in development builds
|
|
15
|
+
* only.
|
|
16
|
+
*
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
const StateTab = (props) => {
|
|
20
|
+
const items = () => props.state.snapshot().nodes.filter((node) => node.type === "signal" || node.type === "store" || node.type === "resource");
|
|
21
|
+
{
|
|
22
|
+
const _el$ = _tmpl$4(), _el$2 = _el$.firstChild;
|
|
23
|
+
insert(_el$2, createComponent(Show, {
|
|
24
|
+
get when() {
|
|
25
|
+
return items().length > 0;
|
|
26
|
+
},
|
|
27
|
+
get fallback() {
|
|
28
|
+
return _tmpl$();
|
|
29
|
+
},
|
|
30
|
+
get children() {
|
|
31
|
+
return createComponent(For, {
|
|
32
|
+
get each() {
|
|
33
|
+
return items();
|
|
34
|
+
},
|
|
35
|
+
key: (node) => node.id,
|
|
36
|
+
children: (node) => {
|
|
37
|
+
const _el$ = _tmpl$3(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling, _el$4 = _el$3.nextSibling;
|
|
38
|
+
effect(() => {
|
|
39
|
+
setAttribute(_el$, "data-id", node().id);
|
|
40
|
+
});
|
|
41
|
+
effect(() => {
|
|
42
|
+
setAttribute(_el$, "aria-selected", props.state.selected() === node().id);
|
|
43
|
+
});
|
|
44
|
+
addEventListener(_el$, "click", () => props.state.select(node().id));
|
|
45
|
+
addEventListener(_el$, "keydown", (event) => {
|
|
46
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
47
|
+
event.preventDefault();
|
|
48
|
+
props.state.select(node().id);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
effect(() => {
|
|
52
|
+
className(_el$2, `kind ${node().type}`);
|
|
53
|
+
});
|
|
54
|
+
insert(_el$2, () => node().type);
|
|
55
|
+
insert(_el$3, () => props.state.nameOf(node().id));
|
|
56
|
+
insert(_el$4, () => node().type === "resource" ? node().state : node().preview);
|
|
57
|
+
insert(_el$, createComponent(Show, {
|
|
58
|
+
get when() {
|
|
59
|
+
return node().writes > 0;
|
|
60
|
+
},
|
|
61
|
+
get children() {
|
|
62
|
+
const _el$ = _tmpl$2();
|
|
63
|
+
insert(_el$, () => node().writes);
|
|
64
|
+
return _el$;
|
|
65
|
+
}
|
|
66
|
+
}, "Show"));
|
|
67
|
+
return _el$;
|
|
68
|
+
}
|
|
69
|
+
}, "For");
|
|
70
|
+
}
|
|
71
|
+
}, "Show"));
|
|
72
|
+
insert(_el$, createComponent(Show, {
|
|
73
|
+
get when() {
|
|
74
|
+
return props.state.selectedNode() !== void 0;
|
|
75
|
+
},
|
|
76
|
+
get children() {
|
|
77
|
+
return createComponent(Details, { get state() {
|
|
78
|
+
return props.state;
|
|
79
|
+
} }, "Details");
|
|
80
|
+
}
|
|
81
|
+
}, "Show"));
|
|
82
|
+
return _el$;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
//#endregion
|
|
86
|
+
export { StateTab };
|
|
87
|
+
|
|
88
|
+
//# sourceMappingURL=state-tab.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-tab.js","names":["_$createComponent"],"sources":["../../../src/ui/state-tab.tsx"],"sourcesContent":["import { For, Show } from \"@shadow-js/web\";\nimport type { Component } from \"@shadow-js/web/jsx-runtime\";\nimport { Details } from \"./details\";\nimport type { TabProps } from \"./tree\";\n\n/**\n * The State tab. Props: `state` is the panel's {@link PanelState}. It lists every signal, store and\n * resource with its current value (and its write count when it is above zero). Selecting a row (click, Enter or Space) shows its\n * details; for signals and stores the details include a value editor, where a change is applied like any\n * other write.\n *\n * Internal to the panel: the package index does not export this component. Used in development builds\n * only.\n *\n * @internal\n */\nexport const StateTab: Component<TabProps> = (props) => {\n const items = () =>\n props.state\n .snapshot()\n .nodes.filter(\n (node) => node.type === \"signal\" || node.type === \"store\" || node.type === \"resource\",\n );\n return (\n <div class=\"split\">\n <div class=\"list\" role=\"listbox\" aria-label=\"State\">\n <Show\n when={items().length > 0}\n fallback={<div class=\"empty\">No signals or stores yet.</div>}\n >\n <For each={items()} key={(node) => node.id}>\n {(node) => (\n <div\n class=\"row\"\n role=\"option\"\n data-id={node().id}\n tabIndex={0}\n aria-selected={props.state.selected() === node().id}\n on:click={() => props.state.select(node().id)}\n on:keydown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n props.state.select(node().id);\n }\n }}\n >\n <span class={`kind ${node().type}`}>{node().type}</span>\n <span class=\"name\">{props.state.nameOf(node().id)}</span>\n <span class=\"value\">\n {node().type === \"resource\" ? node().state : node().preview}\n </span>\n <Show when={node().writes > 0}>\n <span class=\"updates\" title=\"Writes\">\n ×{node().writes}\n </span>\n </Show>\n </div>\n )}\n </For>\n </Show>\n </div>\n <Show when={props.state.selectedNode() !== undefined}>\n <Details state={props.state} />\n </Show>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAgBA,MAAa,YAAiC,UAAU;CACtD,MAAM,cACJ,MAAM,MACH,SAAS,CAAA,CACT,MAAM,QACJ,SAAS,KAAK,SAAS,YAAY,KAAK,SAAS,WAAW,KAAK,SAAS,UAC7E;CACJ;EAAA,MAAA,OAAA,QAAA,GAAA,QAAA,KAAA;EAAA,OAAA,OAAAA,gBAAA,MAAA;GAAA,IAAA,OAAA;IAAA,OAAA,MAAA,CAAA,CAAA,SAAA;GAAA;GAAA,IAAA,WAAA;IAAA,OAAA,OAAA;GAAA;GAAA,IAAA,WAAA;IAAA,OAAAA,gBAAA,KAAA;KAAA,IAAA,OAAA;MAAA,OAAA,MAAA;KAAA;KAAA,MAAA,SAAA,KAAA;KAAA,WAAA,SAAA;MAAA,MAAA,OAAA,QAAA,GAAA,QAAA,KAAA,YAAA,QAAA,MAAA,aAAA,QAAA,MAAA;MAAA,aAAA;OAAA,aAAA,MAAA,WAAA,KAAA,CAAA,CAAA,EAAA;MAAA,CAAA;MAAA,aAAA;OAAA,aAAA,MAAA,iBAAA,MAAA,MAAA,SAAA,MAAA,KAAA,CAAA,CAAA,EAAA;MAAA,CAAA;MAAA,iBAAA,MAAA,eAAA,MAAA,MAAA,OAAA,KAAA,CAAA,CAAA,EAAA,CAAA;MAAA,iBAAA,MAAA,YAAA,UAAA;OAAA,IAAA,MAAA,QAAA,WAAA,MAAA,QAAA,KAAA;QAAA,MAAA,eAAA;QAAA,MAAA,MAAA,OAAA,KAAA,CAAA,CAAA,EAAA;OAAA;MAAA,CAAA;MAAA,aAAA;OAAA,UAAA,OAAA,QAAA,KAAA,CAAA,CAAA,MAAA;MAAA,CAAA;MAAA,OAAA,aAAA,KAAA,CAAA,CAAA,IAAA;MAAA,OAAA,aAAA,MAAA,MAAA,OAAA,KAAA,CAAA,CAAA,EAAA,CAAA;MAAA,OAAA,aAAA,KAAA,CAAA,CAAA,SAAA,aAAA,KAAA,CAAA,CAAA,QAAA,KAAA,CAAA,CAAA,OAAA;MAAA,OAAA,MAAAA,gBAAA,MAAA;OAAA,IAAA,OAAA;QAAA,OAAA,KAAA,CAAA,CAAA,SAAA;OAAA;OAAA,IAAA,WAAA;QAAA,MAAA,OAAA,QAAA;QAAA,OAAA,YAAA,KAAA,CAAA,CAAA,MAAA;QAAA,OAAA;OAAA;MAAA,GAAA,MAAA,CAAA;MAAA,OAAA;KAAA;IAAA,GAAA,KAAA;GAAA;EAAA,GAAA,MAAA,CAAA;EAAA,OAAA,MAAAA,gBAAA,MAAA;GAAA,IAAA,OAAA;IAAA,OAAA,MAAA,MAAA,aAAA,MAAA,KAAA;GAAA;GAAA,IAAA,WAAA;IAAA,OAAAA,gBAAA,SAAA,EAAA,IAAA,QAAA;KAAA,OAAA,MAAA;IAAA,EAAA,GAAA,SAAA;GAAA;EAAA,GAAA,MAAA,CAAA;EAAA,OAAA;CAAA;AA2CF"}
|