@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.
Files changed (112) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +21 -0
  3. package/README.md +576 -2
  4. package/dist/dev/agent.d.ts +239 -0
  5. package/dist/dev/agent.js +626 -0
  6. package/dist/dev/agent.js.map +1 -0
  7. package/dist/dev/backend.d.ts +53 -0
  8. package/dist/dev/backend.js +53 -0
  9. package/dist/dev/backend.js.map +1 -0
  10. package/dist/dev/hook.d.ts +83 -0
  11. package/dist/dev/hook.js +136 -0
  12. package/dist/dev/hook.js.map +1 -0
  13. package/dist/dev/index.d.ts +17 -0
  14. package/dist/dev/index.js +17 -0
  15. package/dist/dev/inspection.d.ts +226 -0
  16. package/dist/dev/inspection.js +263 -0
  17. package/dist/dev/inspection.js.map +1 -0
  18. package/dist/dev/inspector.d.ts +331 -0
  19. package/dist/dev/inspector.js +429 -0
  20. package/dist/dev/inspector.js.map +1 -0
  21. package/dist/dev/model.d.ts +418 -0
  22. package/dist/dev/model.js +559 -0
  23. package/dist/dev/model.js.map +1 -0
  24. package/dist/dev/mount.d.ts +207 -0
  25. package/dist/dev/mount.js +256 -0
  26. package/dist/dev/mount.js.map +1 -0
  27. package/dist/dev/overlay.d.ts +102 -0
  28. package/dist/dev/overlay.js +176 -0
  29. package/dist/dev/overlay.js.map +1 -0
  30. package/dist/dev/preview.d.ts +74 -0
  31. package/dist/dev/preview.js +122 -0
  32. package/dist/dev/preview.js.map +1 -0
  33. package/dist/dev/protocol.d.ts +288 -0
  34. package/dist/dev/protocol.js +109 -0
  35. package/dist/dev/protocol.js.map +1 -0
  36. package/dist/dev/ring.d.ts +50 -0
  37. package/dist/dev/ring.js +94 -0
  38. package/dist/dev/ring.js.map +1 -0
  39. package/dist/dev/transport.d.ts +347 -0
  40. package/dist/dev/transport.js +394 -0
  41. package/dist/dev/transport.js.map +1 -0
  42. package/dist/dev/ui/details.js +294 -0
  43. package/dist/dev/ui/details.js.map +1 -0
  44. package/dist/dev/ui/inspection-state.d.ts +43 -0
  45. package/dist/dev/ui/inspection-state.js +62 -0
  46. package/dist/dev/ui/inspection-state.js.map +1 -0
  47. package/dist/dev/ui/issues.js +85 -0
  48. package/dist/dev/ui/issues.js.map +1 -0
  49. package/dist/dev/ui/panel.d.ts +55 -0
  50. package/dist/dev/ui/panel.js +160 -0
  51. package/dist/dev/ui/panel.js.map +1 -0
  52. package/dist/dev/ui/rows.d.ts +44 -0
  53. package/dist/dev/ui/rows.js +132 -0
  54. package/dist/dev/ui/rows.js.map +1 -0
  55. package/dist/dev/ui/state-tab.js +88 -0
  56. package/dist/dev/ui/state-tab.js.map +1 -0
  57. package/dist/dev/ui/state.d.ts +192 -0
  58. package/dist/dev/ui/state.js +147 -0
  59. package/dist/dev/ui/state.js.map +1 -0
  60. package/dist/dev/ui/styles.d.ts +31 -0
  61. package/dist/dev/ui/styles.js +113 -0
  62. package/dist/dev/ui/styles.js.map +1 -0
  63. package/dist/dev/ui/timeline.js +135 -0
  64. package/dist/dev/ui/timeline.js.map +1 -0
  65. package/dist/dev/ui/tree.js +186 -0
  66. package/dist/dev/ui/tree.js.map +1 -0
  67. package/dist/prod/agent.js +2 -0
  68. package/dist/prod/agent.js.map +1 -0
  69. package/dist/prod/backend.js +2 -0
  70. package/dist/prod/backend.js.map +1 -0
  71. package/dist/prod/hook.js +2 -0
  72. package/dist/prod/hook.js.map +1 -0
  73. package/dist/prod/index.js +1 -0
  74. package/dist/prod/inspection.js +2 -0
  75. package/dist/prod/inspection.js.map +1 -0
  76. package/dist/prod/inspector.js +2 -0
  77. package/dist/prod/inspector.js.map +1 -0
  78. package/dist/prod/model.js +2 -0
  79. package/dist/prod/model.js.map +1 -0
  80. package/dist/prod/mount.js +2 -0
  81. package/dist/prod/mount.js.map +1 -0
  82. package/dist/prod/overlay.js +11 -0
  83. package/dist/prod/overlay.js.map +1 -0
  84. package/dist/prod/preview.js +2 -0
  85. package/dist/prod/preview.js.map +1 -0
  86. package/dist/prod/protocol.js +2 -0
  87. package/dist/prod/protocol.js.map +1 -0
  88. package/dist/prod/ring.js +2 -0
  89. package/dist/prod/ring.js.map +1 -0
  90. package/dist/prod/transport.js +2 -0
  91. package/dist/prod/transport.js.map +1 -0
  92. package/dist/prod/ui/details.js +2 -0
  93. package/dist/prod/ui/details.js.map +1 -0
  94. package/dist/prod/ui/inspection-state.js +2 -0
  95. package/dist/prod/ui/inspection-state.js.map +1 -0
  96. package/dist/prod/ui/issues.js +2 -0
  97. package/dist/prod/ui/issues.js.map +1 -0
  98. package/dist/prod/ui/panel.js +2 -0
  99. package/dist/prod/ui/panel.js.map +1 -0
  100. package/dist/prod/ui/rows.js +2 -0
  101. package/dist/prod/ui/rows.js.map +1 -0
  102. package/dist/prod/ui/state-tab.js +2 -0
  103. package/dist/prod/ui/state-tab.js.map +1 -0
  104. package/dist/prod/ui/state.js +2 -0
  105. package/dist/prod/ui/state.js.map +1 -0
  106. package/dist/prod/ui/styles.js +82 -0
  107. package/dist/prod/ui/styles.js.map +1 -0
  108. package/dist/prod/ui/timeline.js +2 -0
  109. package/dist/prod/ui/timeline.js.map +1 -0
  110. package/dist/prod/ui/tree.js +2 -0
  111. package/dist/prod/ui/tree.js.map +1 -0
  112. package/package.json +69 -4
@@ -0,0 +1,294 @@
1
+ import { For, Show, addEventListener, anchor, className, createComponent, effect, insert, memo, setAttribute, template } from "@shadow-js/web";
2
+ import { untrack, useEffect, useSignal } from "@shadow-js/core";
3
+ //#region src/ui/details.tsx
4
+ const _tmpl$ = /*#__PURE__*/ template("<button type=\"button\" class=\"btn\">Apply</button>");
5
+ const _tmpl$2 = /*#__PURE__*/ template("<button type=\"button\" class=\"btn\">Revert</button>");
6
+ const _tmpl$3 = /*#__PURE__*/ template("<div class=\"section\"><h4>Value</h4><textarea class=\"textarea\" aria-label=\"Value\"></textarea><div><span role=\"status\"></span></div></div>");
7
+ const _tmpl$4 = /*#__PURE__*/ template("<span><button type=\"button\" class=\"link\"></button> </span>");
8
+ const _tmpl$5 = /*#__PURE__*/ template("<li><strong></strong></li>");
9
+ const _tmpl$6 = /*#__PURE__*/ template("<div class=\"status\">Also changed: </div>");
10
+ const _tmpl$7 = /*#__PURE__*/ template("<div class=\"status\">Older history was dropped.</div>");
11
+ const _tmpl$8 = /*#__PURE__*/ template("<div class=\"section\" data-why><h4>Why did it run?</h4><ol class=\"chain\"></ol></div>");
12
+ const _tmpl$9 = /*#__PURE__*/ template("<div class=\"status\"> runs · updates · last ms · total ms</div>");
13
+ const _tmpl$10 = /*#__PURE__*/ template("<div class=\"section\"><h4>Reads</h4></div>");
14
+ const _tmpl$11 = /*#__PURE__*/ template("<div class=\"section\"><h4>Read by</h4></div>");
15
+ const _tmpl$12 = /*#__PURE__*/ template("<section class=\"detail\" aria-label=\"Details\"><div class=\"section\"><strong></strong> <span class=\"status\"> #</span></div></section>");
16
+ /**
17
+ * Shows the value of a signal or store as indented JSON, and edits it. Props: `state` is the panel's
18
+ * {@link PanelState} and `node` is the selected node. Apply writes the text back through the agent, and a
19
+ * successful write re-renders the app like any other write. Revert discards the edit. While the text is
20
+ * being edited, the view does not overwrite it. A resource or a memo has no editor here.
21
+ *
22
+ * Internal to the panel: the package index does not export this component. Used in development builds
23
+ * only.
24
+ *
25
+ * @internal
26
+ */
27
+ const ValueEditor = (props) => {
28
+ const [text, setText] = useSignal("");
29
+ const [dirty, setDirty] = useSignal(false);
30
+ const [editable, setEditable] = useSignal(false);
31
+ const [status, setStatus] = useSignal({
32
+ kind: "idle",
33
+ text: ""
34
+ });
35
+ useEffect(() => {
36
+ props.state.version();
37
+ const id = props.node.id;
38
+ const store = props.node.type === "store";
39
+ if (dirty()) return;
40
+ untrack(() => props.state.backend.request(store ? {
41
+ type: "store",
42
+ id
43
+ } : {
44
+ type: "value",
45
+ id
46
+ })).then((response) => {
47
+ if (!response.ok) {
48
+ setStatus({
49
+ kind: "bad",
50
+ text: response.error
51
+ });
52
+ return;
53
+ }
54
+ const result = response.result;
55
+ setText(result.text);
56
+ setEditable(result.editable);
57
+ });
58
+ });
59
+ const apply = () => {
60
+ const id = props.node.id;
61
+ const request = props.node.type === "store" ? {
62
+ type: "store-set",
63
+ id,
64
+ path: [],
65
+ text: text()
66
+ } : {
67
+ type: "write",
68
+ id,
69
+ text: text()
70
+ };
71
+ props.state.backend.request(request).then((response) => {
72
+ if (response.ok) {
73
+ setDirty(false);
74
+ setStatus({
75
+ kind: "good",
76
+ text: "Applied."
77
+ });
78
+ props.state.refresh();
79
+ } else setStatus({
80
+ kind: "bad",
81
+ text: response.error
82
+ });
83
+ });
84
+ };
85
+ {
86
+ const _el$ = _tmpl$3(), _el$2 = _el$.firstChild.nextSibling, _el$3 = _el$2.nextSibling, _el$4 = _el$3.firstChild, _el$5 = anchor(_el$3, _el$4);
87
+ effect(() => {
88
+ setAttribute(_el$, "data-editor", props.node.type);
89
+ });
90
+ setAttribute(_el$2, "spellcheck", false);
91
+ effect(() => {
92
+ _el$2.readOnly = !editable();
93
+ });
94
+ addEventListener(_el$2, "input", (event) => {
95
+ setText(event.currentTarget.value);
96
+ setDirty(true);
97
+ setStatus({
98
+ kind: "idle",
99
+ text: ""
100
+ });
101
+ });
102
+ effect(() => {
103
+ _el$2.value = text() ?? "";
104
+ });
105
+ insert(_el$3, createComponent(Show, {
106
+ get when() {
107
+ return editable();
108
+ },
109
+ get children() {
110
+ return [(() => {
111
+ const _el$ = _tmpl$();
112
+ effect(() => {
113
+ _el$.disabled = !dirty();
114
+ });
115
+ addEventListener(_el$, "click", apply);
116
+ return _el$;
117
+ })(), " "];
118
+ }
119
+ }, "Show"), _el$5);
120
+ insert(_el$3, createComponent(Show, {
121
+ get when() {
122
+ return dirty();
123
+ },
124
+ get children() {
125
+ return [(() => {
126
+ const _el$ = _tmpl$2();
127
+ addEventListener(_el$, "click", () => {
128
+ setDirty(false);
129
+ props.state.refresh();
130
+ });
131
+ return _el$;
132
+ })(), " "];
133
+ }
134
+ }, "Show"), _el$4);
135
+ effect(() => {
136
+ className(_el$4, `status ${status().kind}`);
137
+ });
138
+ insert(_el$4, () => status().text);
139
+ return _el$;
140
+ }
141
+ };
142
+ /**
143
+ * The selected node: its name and kind, its counters (runs, updates and durations for memos and effects),
144
+ * what it reads, who reads it, why it last ran (memos and effects), and a {@link ValueEditor} for signals
145
+ * and stores. Props: `state` is the panel's {@link PanelState}. It renders nothing when no node is
146
+ * selected.
147
+ *
148
+ * Internal to the panel: the package index does not export this component. Used in development builds
149
+ * only.
150
+ *
151
+ * @internal
152
+ */
153
+ const Details = (props) => createComponent(Show, {
154
+ get when() {
155
+ return props.state.selectedNode();
156
+ },
157
+ children: (node) => {
158
+ const _el$ = _tmpl$12(), _el$2 = _el$.firstChild, _el$6 = _el$2.firstChild, _el$7 = _el$6.nextSibling.nextSibling, _el$8 = _el$7.firstChild, _el$3 = anchor(_el$, null), _el$4 = anchor(_el$, null), _el$5 = anchor(_el$, null);
159
+ insert(_el$6, () => props.state.nameOf(node().id));
160
+ insert(_el$7, () => node().type, _el$8);
161
+ insert(_el$7, () => node().id);
162
+ insert(_el$2, createComponent(Show, {
163
+ get when() {
164
+ return node().type === "memo" || node().type === "effect";
165
+ },
166
+ get children() {
167
+ const _el$ = _tmpl$9(), _el$2 = _el$.firstChild, _el$3 = _el$2.splitText(8), _el$4 = _el$3.splitText(16), _el$5 = _el$4.splitText(12);
168
+ insert(_el$, () => node().runs, _el$2);
169
+ insert(_el$, () => node().updates, _el$3);
170
+ insert(_el$, () => node().lastDuration.toFixed(2), _el$4);
171
+ insert(_el$, () => node().totalDuration.toFixed(2), _el$5);
172
+ return _el$;
173
+ }
174
+ }, "Show"));
175
+ insert(_el$, createComponent(Show, {
176
+ get when() {
177
+ return node().sources.length > 0;
178
+ },
179
+ get children() {
180
+ const _el$ = _tmpl$10();
181
+ insert(_el$, createComponent(For, {
182
+ get each() {
183
+ return node().sources;
184
+ },
185
+ children: (id) => {
186
+ const _el$ = _tmpl$4(), _el$2 = _el$.firstChild;
187
+ addEventListener(_el$2, "click", () => props.state.select(id));
188
+ insert(_el$2, () => props.state.nameOf(id));
189
+ return _el$;
190
+ }
191
+ }, "For"));
192
+ return _el$;
193
+ }
194
+ }, "Show"), _el$3);
195
+ insert(_el$, createComponent(Show, {
196
+ get when() {
197
+ return node().observers.length > 0;
198
+ },
199
+ get children() {
200
+ const _el$ = _tmpl$11();
201
+ insert(_el$, createComponent(For, {
202
+ get each() {
203
+ return node().observers;
204
+ },
205
+ children: (id) => {
206
+ const _el$ = _tmpl$4(), _el$2 = _el$.firstChild;
207
+ addEventListener(_el$2, "click", () => props.state.select(id));
208
+ insert(_el$2, () => props.state.nameOf(id));
209
+ return _el$;
210
+ }
211
+ }, "For"));
212
+ return _el$;
213
+ }
214
+ }, "Show"), _el$4);
215
+ insert(_el$, createComponent(Show, {
216
+ get when() {
217
+ return props.state.explanation();
218
+ },
219
+ children: (why) => {
220
+ const _el$ = _tmpl$8(), _el$2 = _el$.firstChild.nextSibling, _el$3 = anchor(_el$, null);
221
+ insert(_el$2, createComponent(For, {
222
+ get each() {
223
+ return why().chain;
224
+ },
225
+ children: (step) => {
226
+ const _el$ = _tmpl$5(), _el$2 = _el$.firstChild, _el$3 = anchor(_el$, null);
227
+ insert(_el$, () => step.kind === "write" ? "write " : step.kind === "run" ? "ran " : "", _el$2);
228
+ insert(_el$2, () => step.label);
229
+ insert(_el$, createComponent(Show, {
230
+ get when() {
231
+ return step.preview !== void 0;
232
+ },
233
+ get children() {
234
+ return [" = ", memo(() => step.preview)];
235
+ }
236
+ }, "Show"), _el$3);
237
+ insert(_el$, createComponent(Show, {
238
+ get when() {
239
+ return step.writer !== void 0;
240
+ },
241
+ get children() {
242
+ return [
243
+ " (written by ",
244
+ memo(() => step.writer),
245
+ ")"
246
+ ];
247
+ }
248
+ }, "Show"));
249
+ return _el$;
250
+ }
251
+ }, "For"));
252
+ insert(_el$, createComponent(Show, {
253
+ get when() {
254
+ return why().alsoCausedBy.length > 0;
255
+ },
256
+ get children() {
257
+ const _el$ = _tmpl$6();
258
+ insert(_el$, () => why().alsoCausedBy.map((step) => step.label).join(", "));
259
+ return _el$;
260
+ }
261
+ }, "Show"), _el$3);
262
+ insert(_el$, createComponent(Show, {
263
+ get when() {
264
+ return why().truncated;
265
+ },
266
+ get children() {
267
+ return _tmpl$7();
268
+ }
269
+ }, "Show"));
270
+ return _el$;
271
+ }
272
+ }, "Show"), _el$5);
273
+ insert(_el$, createComponent(Show, {
274
+ get when() {
275
+ return node().type === "signal" || node().type === "store";
276
+ },
277
+ get children() {
278
+ return createComponent(ValueEditor, {
279
+ get state() {
280
+ return props.state;
281
+ },
282
+ get node() {
283
+ return node();
284
+ }
285
+ }, "ValueEditor");
286
+ }
287
+ }, "Show"));
288
+ return _el$;
289
+ }
290
+ }, "Show");
291
+ //#endregion
292
+ export { Details, ValueEditor };
293
+
294
+ //# sourceMappingURL=details.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"details.js","names":["_$anchor","_$createComponent","_$memo"],"sources":["../../../src/ui/details.tsx"],"sourcesContent":["import { untrack, useEffect, useSignal } from \"@shadow-js/core\";\nimport { For, Show } from \"@shadow-js/web\";\nimport type { Component } from \"@shadow-js/web/jsx-runtime\";\nimport type { AgentRequest } from \"../agent\";\nimport type { SnapshotNode } from \"../inspector\";\nimport type { PanelState } from \"./state\";\n\ninterface NodeProps {\n state: PanelState;\n node: SnapshotNode;\n}\n\n/**\n * Shows the value of a signal or store as indented JSON, and edits it. Props: `state` is the panel's\n * {@link PanelState} and `node` is the selected node. Apply writes the text back through the agent, and a\n * successful write re-renders the app like any other write. Revert discards the edit. While the text is\n * being edited, the view does not overwrite it. A resource or a memo has no editor here.\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 ValueEditor: Component<NodeProps> = (props) => {\n const [text, setText] = useSignal(\"\");\n const [dirty, setDirty] = useSignal(false);\n const [editable, setEditable] = useSignal(false);\n const [status, setStatus] = useSignal({ kind: \"idle\", text: \"\" });\n\n useEffect(() => {\n // Follow the value while it changes, unless the user is typing.\n props.state.version();\n const id = props.node.id;\n const store = props.node.type === \"store\";\n if (dirty()) return;\n // The request reads the value through the agent; the reads above are the only dependencies.\n const request = untrack(() =>\n props.state.backend.request(store ? { type: \"store\", id } : { type: \"value\", id }),\n );\n void request.then((response) => {\n if (!response.ok) {\n setStatus({ kind: \"bad\", text: response.error });\n return;\n }\n const result = response.result as { text: string; editable: boolean };\n setText(result.text);\n setEditable(result.editable);\n });\n });\n\n const apply = (): void => {\n const id = props.node.id;\n const request: AgentRequest =\n props.node.type === \"store\"\n ? { type: \"store-set\", id, path: [], text: text() }\n : { type: \"write\", id, text: text() };\n void props.state.backend.request(request).then((response) => {\n if (response.ok) {\n setDirty(false);\n setStatus({ kind: \"good\", text: \"Applied.\" });\n props.state.refresh();\n } else {\n setStatus({ kind: \"bad\", text: response.error });\n }\n });\n };\n\n return (\n <div class=\"section\" data-editor={props.node.type}>\n <h4>Value</h4>\n <textarea\n class=\"textarea\"\n aria-label=\"Value\"\n spellcheck={false}\n readOnly={!editable()}\n value={text()}\n on:input={(event) => {\n setText(event.currentTarget.value);\n setDirty(true);\n setStatus({ kind: \"idle\", text: \"\" });\n }}\n />\n <div>\n <Show when={editable()}>\n <button type=\"button\" class=\"btn\" disabled={!dirty()} on:click={apply}>\n Apply\n </button>{\" \"}\n </Show>\n <Show when={dirty()}>\n <button\n type=\"button\"\n class=\"btn\"\n on:click={() => {\n setDirty(false);\n props.state.refresh();\n }}\n >\n Revert\n </button>{\" \"}\n </Show>\n <span class={`status ${status().kind}`} role=\"status\">\n {status().text}\n </span>\n </div>\n </div>\n );\n};\n\n/** Props of {@link Details}. */\ninterface DetailsProps {\n state: PanelState;\n}\n\n/**\n * The selected node: its name and kind, its counters (runs, updates and durations for memos and effects),\n * what it reads, who reads it, why it last ran (memos and effects), and a {@link ValueEditor} for signals\n * and stores. Props: `state` is the panel's {@link PanelState}. It renders nothing when no node is\n * selected.\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 Details: Component<DetailsProps> = (props) => (\n <Show when={props.state.selectedNode()}>\n {(node) => (\n <section class=\"detail\" aria-label=\"Details\">\n <div class=\"section\">\n <strong>{props.state.nameOf(node().id)}</strong>{\" \"}\n <span class=\"status\">\n {node().type} #{node().id}\n </span>\n <Show when={node().type === \"memo\" || node().type === \"effect\"}>\n <div class=\"status\">\n {node().runs} runs · {node().updates} updates · last {node().lastDuration.toFixed(2)}{\" \"}\n ms · total {node().totalDuration.toFixed(2)} ms\n </div>\n </Show>\n </div>\n <Show when={node().sources.length > 0}>\n <div class=\"section\">\n <h4>Reads</h4>\n <For each={node().sources}>\n {(id) => (\n <span>\n <button type=\"button\" class=\"link\" on:click={() => props.state.select(id)}>\n {props.state.nameOf(id)}\n </button>{\" \"}\n </span>\n )}\n </For>\n </div>\n </Show>\n <Show when={node().observers.length > 0}>\n <div class=\"section\">\n <h4>Read by</h4>\n <For each={node().observers}>\n {(id) => (\n <span>\n <button type=\"button\" class=\"link\" on:click={() => props.state.select(id)}>\n {props.state.nameOf(id)}\n </button>{\" \"}\n </span>\n )}\n </For>\n </div>\n </Show>\n <Show when={props.state.explanation()}>\n {(why) => (\n <div class=\"section\" data-why>\n <h4>Why did it run?</h4>\n <ol class=\"chain\">\n <For each={why().chain}>\n {(step) => (\n <li>\n {step.kind === \"write\" ? \"write \" : step.kind === \"run\" ? \"ran \" : \"\"}\n <strong>{step.label}</strong>\n <Show when={step.preview !== undefined}> = {step.preview}</Show>\n <Show when={step.writer !== undefined}> (written by {step.writer})</Show>\n </li>\n )}\n </For>\n </ol>\n <Show when={why().alsoCausedBy.length > 0}>\n <div class=\"status\">\n Also changed:{\" \"}\n {why()\n .alsoCausedBy.map((step) => step.label)\n .join(\", \")}\n </div>\n </Show>\n <Show when={why().truncated}>\n <div class=\"status\">Older history was dropped.</div>\n </Show>\n </div>\n )}\n </Show>\n <Show when={node().type === \"signal\" || node().type === \"store\"}>\n <ValueEditor state={props.state} node={node()} />\n </Show>\n </section>\n )}\n </Show>\n);\n"],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { InspectionSnapshot } from "../inspection.js";
2
+ import { Backend } from "../backend.js";
3
+ import { Accessor } from "@shadow-js/core";
4
+ //#region src/ui/inspection-state.d.ts
5
+ /**
6
+ * What the inspection views of a remote panel read and write: the registered sources, the one on
7
+ * screen, and the state of the last request. Built by {@link createInspectionState}.
8
+ *
9
+ * @since 1.0.0
10
+ */
11
+ export interface InspectionState {
12
+ /** The sources the page answered with at the last refresh (empty before the first one). */
13
+ readonly sources: Accessor<readonly InspectionSnapshot[]>;
14
+ /** The name of the source on screen, or `""` when there is none. */
15
+ readonly active: Accessor<string>;
16
+ /** The reason the last refresh failed, or `""` when it did not. */
17
+ readonly error: Accessor<string>;
18
+ /** True while a refresh is waiting for the page. */
19
+ readonly loading: Accessor<boolean>;
20
+ /** Shows the source registered as `name`. Ignored when no source has that name. */
21
+ select(name: string): void;
22
+ /** Asks the page for its sources now. Resolves when the answer arrived (or failed). */
23
+ refresh(): Promise<void>;
24
+ }
25
+ /**
26
+ * The state of the inspection views of a panel (the router and query tabs): it asks the agent for the
27
+ * registered sources, keeps the answer, and remembers which source is shown. It talks only to a
28
+ * {@link Backend}, so it works for a local agent and for a remote one. An answer that does not have
29
+ * the expected shape is refused and reported as an error; the previous sources stay.
30
+ *
31
+ * @param backend The backend to ask.
32
+ * @returns The inspection state.
33
+ * @example
34
+ * import { createInspectionState, createLocalBackend, createAgent } from "@shadow-js/devtools";
35
+ *
36
+ * const state = createInspectionState(createLocalBackend(createAgent()));
37
+ * await state.refresh();
38
+ * state.sources(); // the registered sources
39
+ * @since 1.0.0
40
+ */
41
+ export declare function createInspectionState(backend: Backend): InspectionState;
42
+ //#endregion
43
+ //# sourceMappingURL=inspection-state.d.ts.map
@@ -0,0 +1,62 @@
1
+ import { parseInspectResult } from "../inspection.js";
2
+ import { useSignal } from "@shadow-js/core";
3
+ //#region src/ui/inspection-state.ts
4
+ /**
5
+ * The state of the inspection views of a panel (the router and query tabs): it asks the agent for the
6
+ * registered sources, keeps the answer, and remembers which source is shown. It talks only to a
7
+ * {@link Backend}, so it works for a local agent and for a remote one. An answer that does not have
8
+ * the expected shape is refused and reported as an error; the previous sources stay.
9
+ *
10
+ * @param backend The backend to ask.
11
+ * @returns The inspection state.
12
+ * @example
13
+ * import { createInspectionState, createLocalBackend, createAgent } from "@shadow-js/devtools";
14
+ *
15
+ * const state = createInspectionState(createLocalBackend(createAgent()));
16
+ * await state.refresh();
17
+ * state.sources(); // the registered sources
18
+ * @since 1.0.0
19
+ */
20
+ function createInspectionState(backend) {
21
+ const [sources, setSources] = useSignal([]);
22
+ const [active, setActive] = useSignal("");
23
+ const [error, setError] = useSignal("");
24
+ const [loading, setLoading] = useSignal(false);
25
+ const select = (name) => {
26
+ if (sources().some((source) => source.name === name)) setActive(name);
27
+ };
28
+ const refresh = async () => {
29
+ setLoading(true);
30
+ try {
31
+ const response = await backend.request({ type: "inspect" });
32
+ if (!response.ok) {
33
+ setError(response.error);
34
+ return;
35
+ }
36
+ const parsed = parseInspectResult(response.result);
37
+ if (parsed === null) {
38
+ setError("The page answered the inspect request with an unexpected value.");
39
+ return;
40
+ }
41
+ setSources(parsed);
42
+ setError("");
43
+ if (!parsed.some((source) => source.name === active())) setActive(parsed[0]?.name ?? "");
44
+ } catch (failure) {
45
+ setError(failure instanceof Error ? failure.message : "The request failed.");
46
+ } finally {
47
+ setLoading(false);
48
+ }
49
+ };
50
+ return {
51
+ sources,
52
+ active,
53
+ error,
54
+ loading,
55
+ select,
56
+ refresh
57
+ };
58
+ }
59
+ //#endregion
60
+ export { createInspectionState };
61
+
62
+ //# sourceMappingURL=inspection-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspection-state.js","names":[],"sources":["../../../src/ui/inspection-state.ts"],"sourcesContent":["import { type Accessor, useSignal } from \"@shadow-js/core\";\nimport type { Backend } from \"../backend\";\nimport { type InspectionSnapshot, parseInspectResult } from \"../inspection\";\n\n/**\n * What the inspection views of a remote panel read and write: the registered sources, the one on\n * screen, and the state of the last request. Built by {@link createInspectionState}.\n *\n * @since 1.0.0\n */\nexport interface InspectionState {\n /** The sources the page answered with at the last refresh (empty before the first one). */\n readonly sources: Accessor<readonly InspectionSnapshot[]>;\n /** The name of the source on screen, or `\"\"` when there is none. */\n readonly active: Accessor<string>;\n /** The reason the last refresh failed, or `\"\"` when it did not. */\n readonly error: Accessor<string>;\n /** True while a refresh is waiting for the page. */\n readonly loading: Accessor<boolean>;\n /** Shows the source registered as `name`. Ignored when no source has that name. */\n select(name: string): void;\n /** Asks the page for its sources now. Resolves when the answer arrived (or failed). */\n refresh(): Promise<void>;\n}\n\n/**\n * The state of the inspection views of a panel (the router and query tabs): it asks the agent for the\n * registered sources, keeps the answer, and remembers which source is shown. It talks only to a\n * {@link Backend}, so it works for a local agent and for a remote one. An answer that does not have\n * the expected shape is refused and reported as an error; the previous sources stay.\n *\n * @param backend The backend to ask.\n * @returns The inspection state.\n * @example\n * import { createInspectionState, createLocalBackend, createAgent } from \"@shadow-js/devtools\";\n *\n * const state = createInspectionState(createLocalBackend(createAgent()));\n * await state.refresh();\n * state.sources(); // the registered sources\n * @since 1.0.0\n */\nexport function createInspectionState(backend: Backend): InspectionState {\n const [sources, setSources] = useSignal<readonly InspectionSnapshot[]>([]);\n const [active, setActive] = useSignal(\"\");\n const [error, setError] = useSignal(\"\");\n const [loading, setLoading] = useSignal(false);\n\n const select = (name: string): void => {\n if (sources().some((source) => source.name === name)) setActive(name);\n };\n\n const refresh = async (): Promise<void> => {\n setLoading(true);\n try {\n const response = await backend.request({ type: \"inspect\" });\n if (!response.ok) {\n setError(response.error);\n return;\n }\n const parsed = parseInspectResult(response.result);\n if (parsed === null) {\n setError(\"The page answered the inspect request with an unexpected value.\");\n return;\n }\n setSources(parsed);\n setError(\"\");\n if (!parsed.some((source) => source.name === active())) {\n setActive(parsed[0]?.name ?? \"\");\n }\n } catch (failure) {\n setError(failure instanceof Error ? failure.message : \"The request failed.\");\n } finally {\n setLoading(false);\n }\n };\n\n return { sources, active, error, loading, select, refresh };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAyCA,SAAgB,sBAAsB,SAAmC;CACvE,MAAM,CAAC,SAAS,cAAc,UAAyC,CAAC,CAAC;CACzE,MAAM,CAAC,QAAQ,aAAa,UAAU,EAAE;CACxC,MAAM,CAAC,OAAO,YAAY,UAAU,EAAE;CACtC,MAAM,CAAC,SAAS,cAAc,UAAU,KAAK;CAE7C,MAAM,UAAU,SAAuB;EACrC,IAAI,QAAQ,CAAC,CAAC,MAAM,WAAW,OAAO,SAAS,IAAI,GAAG,UAAU,IAAI;CACtE;CAEA,MAAM,UAAU,YAA2B;EACzC,WAAW,IAAI;EACf,IAAI;GACF,MAAM,WAAW,MAAM,QAAQ,QAAQ,EAAE,MAAM,UAAU,CAAC;GAC1D,IAAI,CAAC,SAAS,IAAI;IAChB,SAAS,SAAS,KAAK;IACvB;GACF;GACA,MAAM,SAAS,mBAAmB,SAAS,MAAM;GACjD,IAAI,WAAW,MAAM;IACnB,SAAS,iEAAiE;IAC1E;GACF;GACA,WAAW,MAAM;GACjB,SAAS,EAAE;GACX,IAAI,CAAC,OAAO,MAAM,WAAW,OAAO,SAAS,OAAO,CAAC,GACnD,UAAU,OAAO,EAAE,EAAE,QAAQ,EAAE;EAEnC,SAAS,SAAS;GAChB,SAAS,mBAAmB,QAAQ,QAAQ,UAAU,qBAAqB;EAC7E,UAAU;GACR,WAAW,KAAK;EAClB;CACF;CAEA,OAAO;EAAE;EAAS;EAAQ;EAAO;EAAS;EAAQ;CAAQ;AAC5D"}
@@ -0,0 +1,85 @@
1
+ import { For, Show, addEventListener, anchor, createComponent, insert, template } from "@shadow-js/web";
2
+ //#region src/ui/issues.tsx
3
+ const _tmpl$ = /*#__PURE__*/ template("<div class=\"empty\">No errors or hydration mismatches.</div>");
4
+ const _tmpl$2 = /*#__PURE__*/ template("<code></code>");
5
+ const _tmpl$3 = /*#__PURE__*/ template("<button type=\"button\" class=\"link\"></button>");
6
+ const _tmpl$4 = /*#__PURE__*/ template("<div class=\"issue\" data-issue=\"error\"></div>");
7
+ const _tmpl$5 = /*#__PURE__*/ template("<div class=\"issue\" data-issue=\"hydration\"><strong>Hydration mismatch:</strong> <div class=\"status\">server: </div><div class=\"status\">client: </div></div>");
8
+ const _tmpl$6 = /*#__PURE__*/ template("<section class=\"list\" aria-label=\"Issues\"></section>");
9
+ /**
10
+ * The Issues tab. Props: `state` is the panel's {@link PanelState}. It lists the errors the runtime reported,
11
+ * with their diagnostic code when there is one and a link to the node they belong to, then the hydration
12
+ * mismatches: the runtime's message, the expected value (labeled server) and the actual value (labeled
13
+ * client).
14
+ *
15
+ * Internal to the panel: the package index does not export this component. Used in development builds
16
+ * only.
17
+ *
18
+ * @internal
19
+ */
20
+ const IssuesTab = (props) => {
21
+ const _el$ = _tmpl$6();
22
+ insert(_el$, createComponent(Show, {
23
+ get when() {
24
+ return props.state.errors().length + props.state.hydration().length > 0;
25
+ },
26
+ get fallback() {
27
+ return _tmpl$();
28
+ },
29
+ get children() {
30
+ return [createComponent(For, {
31
+ get each() {
32
+ return props.state.errors();
33
+ },
34
+ key: (error) => error.seq,
35
+ children: (error) => {
36
+ const _el$ = _tmpl$4(), _el$2 = anchor(_el$, null), _el$3 = anchor(_el$, null);
37
+ insert(_el$, createComponent(Show, {
38
+ get when() {
39
+ return error().code !== void 0;
40
+ },
41
+ get children() {
42
+ return [(() => {
43
+ const _el$ = _tmpl$2();
44
+ insert(_el$, () => error().code);
45
+ return _el$;
46
+ })(), " "];
47
+ }
48
+ }, "Show"), _el$2);
49
+ insert(_el$, () => error().message, _el$3);
50
+ insert(_el$, createComponent(Show, {
51
+ get when() {
52
+ return error().id !== 0;
53
+ },
54
+ get children() {
55
+ return [" ", (() => {
56
+ const _el$ = _tmpl$3();
57
+ addEventListener(_el$, "click", () => props.state.select(error().id));
58
+ insert(_el$, () => props.state.nameOf(error().id));
59
+ return _el$;
60
+ })()];
61
+ }
62
+ }, "Show"));
63
+ return _el$;
64
+ }
65
+ }, "For"), createComponent(For, {
66
+ get each() {
67
+ return props.state.hydration();
68
+ },
69
+ key: (mismatch) => mismatch.seq,
70
+ children: (mismatch) => {
71
+ const _el$ = _tmpl$5(), _el$2 = _el$.firstChild.nextSibling.nextSibling, _el$3 = _el$2.nextSibling;
72
+ insert(_el$, () => mismatch().message, _el$2);
73
+ insert(_el$2, () => mismatch().expected);
74
+ insert(_el$3, () => mismatch().actual);
75
+ return _el$;
76
+ }
77
+ }, "For")];
78
+ }
79
+ }, "Show"));
80
+ return _el$;
81
+ };
82
+ //#endregion
83
+ export { IssuesTab };
84
+
85
+ //# sourceMappingURL=issues.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issues.js","names":["_$createComponent","_$anchor"],"sources":["../../../src/ui/issues.tsx"],"sourcesContent":["import { For, Show } from \"@shadow-js/web\";\nimport type { Component } from \"@shadow-js/web/jsx-runtime\";\nimport type { TabProps } from \"./tree\";\n\n/**\n * The Issues tab. Props: `state` is the panel's {@link PanelState}. It lists the errors the runtime reported,\n * with their diagnostic code when there is one and a link to the node they belong to, then the hydration\n * mismatches: the runtime's message, the expected value (labeled server) and the actual value (labeled\n * client).\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 IssuesTab: Component<TabProps> = (props) => (\n <section class=\"list\" aria-label=\"Issues\">\n <Show\n when={props.state.errors().length + props.state.hydration().length > 0}\n fallback={<div class=\"empty\">No errors or hydration mismatches.</div>}\n >\n <For each={props.state.errors()} key={(error) => error.seq}>\n {(error) => (\n <div class=\"issue\" data-issue=\"error\">\n <Show when={error().code !== undefined}>\n <code>{error().code}</code>{\" \"}\n </Show>\n {error().message}\n <Show when={error().id !== 0}>\n {\" \"}\n <button type=\"button\" class=\"link\" on:click={() => props.state.select(error().id)}>\n {props.state.nameOf(error().id)}\n </button>\n </Show>\n </div>\n )}\n </For>\n <For each={props.state.hydration()} key={(mismatch) => mismatch.seq}>\n {(mismatch) => (\n <div class=\"issue\" data-issue=\"hydration\">\n <strong>Hydration mismatch:</strong> {mismatch().message}\n <div class=\"status\">server: {mismatch().expected}</div>\n <div class=\"status\">client: {mismatch().actual}</div>\n </div>\n )}\n </For>\n </Show>\n </section>\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAeA,MAAa,aAAkC,UAAU;CAAA,MAAA,OAAA,QAAA;CAAA,OAAA,MAAAA,gBAAA,MAAA;EAAA,IAAA,OAAA;GAAA,OAAA,MAAA,MAAA,OAAA,CAAA,CAAA,SAAA,MAAA,MAAA,UAAA,CAAA,CAAA,SAAA;EAAA;EAAA,IAAA,WAAA;GAAA,OAAA,OAAA;EAAA;EAAA,IAAA,WAAA;GAAA,OAAA,CAAAA,gBAAA,KAAA;IAAA,IAAA,OAAA;KAAA,OAAA,MAAA,MAAA,OAAA;IAAA;IAAA,MAAA,UAAA,MAAA;IAAA,WAAA,UAAA;KAAA,MAAA,OAAA,QAAA,GAAA,QAAAC,OAAA,MAAA,IAAA,GAAA,QAAAA,OAAA,MAAA,IAAA;KAAA,OAAA,MAAAD,gBAAA,MAAA;MAAA,IAAA,OAAA;OAAA,OAAA,MAAA,CAAA,CAAA,SAAA,KAAA;MAAA;MAAA,IAAA,WAAA;OAAA,OAAA,QAAA;QAAA,MAAA,OAAA,QAAA;QAAA,OAAA,YAAA,MAAA,CAAA,CAAA,IAAA;QAAA,OAAA;OAAA,EAAA,CAAA,GAAA,GAAA;MAAA;KAAA,GAAA,MAAA,GAAA,KAAA;KAAA,OAAA,YAAA,MAAA,CAAA,CAAA,SAAA,KAAA;KAAA,OAAA,MAAAA,gBAAA,MAAA;MAAA,IAAA,OAAA;OAAA,OAAA,MAAA,CAAA,CAAA,OAAA;MAAA;MAAA,IAAA,WAAA;OAAA,OAAA,CAAA,YAAA;QAAA,MAAA,OAAA,QAAA;QAAA,iBAAA,MAAA,eAAA,MAAA,MAAA,OAAA,MAAA,CAAA,CAAA,EAAA,CAAA;QAAA,OAAA,YAAA,MAAA,MAAA,OAAA,MAAA,CAAA,CAAA,EAAA,CAAA;QAAA,OAAA;OAAA,EAAA,CAAA,CAAA;MAAA;KAAA,GAAA,MAAA,CAAA;KAAA,OAAA;IAAA;GAAA,GAAA,KAAA,GAAAA,gBAAA,KAAA;IAAA,IAAA,OAAA;KAAA,OAAA,MAAA,MAAA,UAAA;IAAA;IAAA,MAAA,aAAA,SAAA;IAAA,WAAA,aAAA;KAAA,MAAA,OAAA,QAAA,GAAA,QAAA,KAAA,WAAA,YAAA,aAAA,QAAA,MAAA;KAAA,OAAA,YAAA,SAAA,CAAA,CAAA,SAAA,KAAA;KAAA,OAAA,aAAA,SAAA,CAAA,CAAA,QAAA;KAAA,OAAA,aAAA,SAAA,CAAA,CAAA,MAAA;KAAA,OAAA;IAAA;GAAA,GAAA,KAAA,CAAA;EAAA;CAAA,GAAA,MAAA,CAAA;CAAA,OAAA;AAAA"}
@@ -0,0 +1,55 @@
1
+ import { PanelState } from "./state.js";
2
+ import { Component } from "@shadow-js/web/jsx-runtime";
3
+ //#region src/ui/panel.d.ts
4
+ /**
5
+ * Props of {@link Panel}.
6
+ *
7
+ * @since 1.0.0
8
+ */
9
+ export interface PanelProps {
10
+ /**
11
+ * The panel's state, from {@link createPanelState}.
12
+ */
13
+ state: PanelState;
14
+ /**
15
+ * Whether the panel is shown. A closed panel keeps its state and is hidden.
16
+ */
17
+ open: boolean;
18
+ /**
19
+ * Left edge of the panel in pixels.
20
+ */
21
+ x: number;
22
+ /**
23
+ * Top edge of the panel in pixels.
24
+ */
25
+ y: number;
26
+ /**
27
+ * Called while the header is dragged, with the new position in pixels. The panel does not move itself;
28
+ * the owner sets `x` and `y`.
29
+ */
30
+ onMove(x: number, y: number): void;
31
+ /**
32
+ * Called when the close button is pressed.
33
+ */
34
+ onClose(): void;
35
+ }
36
+ /**
37
+ * The devtools panel: a header with the drag handle and the Pause, Flash, Clear and close controls, the
38
+ * tabs (Components, Timeline, State, Issues), the active view and a footer with counts. It only talks to
39
+ * {@link PanelState}, so it works the same on a local agent and on a remote one.
40
+ *
41
+ * Development tool: `mountDevtools()` renders it in development builds only, and it never ships in
42
+ * production builds.
43
+ *
44
+ * @example
45
+ * import { createAgent, createLocalBackend, createPanelState, Panel } from "@shadow-js/devtools";
46
+ * const backend = createLocalBackend(createAgent());
47
+ * export const Devtools = () => {
48
+ * const state = createPanelState(backend);
49
+ * return <Panel state={state} open={true} x={16} y={16} onMove={() => undefined} onClose={() => undefined} />;
50
+ * };
51
+ * @since 1.0.0
52
+ */
53
+ export declare const Panel: Component<PanelProps>;
54
+ //#endregion
55
+ //# sourceMappingURL=panel.d.ts.map