@mcp-b/interactive-components 0.2.21 → 0.3.0

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.
@@ -757,15 +757,6 @@
757
757
  },
758
758
  "privacy": "private"
759
759
  },
760
- {
761
- "kind": "field",
762
- "name": "_dark",
763
- "type": {
764
- "text": "boolean"
765
- },
766
- "privacy": "private",
767
- "default": "false"
768
- },
769
760
  {
770
761
  "kind": "field",
771
762
  "name": "_view",
@@ -790,12 +781,6 @@
790
781
  "privacy": "private",
791
782
  "default": "new Compartment()"
792
783
  },
793
- {
794
- "kind": "field",
795
- "name": "_themeCompartment",
796
- "privacy": "private",
797
- "default": "new Compartment()"
798
- },
799
784
  {
800
785
  "kind": "field",
801
786
  "name": "_readonlyCompartment",
@@ -817,41 +802,6 @@
817
802
  "privacy": "private",
818
803
  "default": "false"
819
804
  },
820
- {
821
- "kind": "field",
822
- "name": "_themeObserver",
823
- "type": {
824
- "text": "MutationObserver | null",
825
- "references": [
826
- {
827
- "name": "MutationObserver",
828
- "package": "dom",
829
- "start": 0,
830
- "end": 16
831
- }
832
- ]
833
- },
834
- "privacy": "private",
835
- "default": "null"
836
- },
837
- {
838
- "kind": "field",
839
- "name": "_systemTheme",
840
- "type": {
841
- "text": "MediaQueryList | null"
842
- },
843
- "privacy": "private",
844
- "default": "null"
845
- },
846
- {
847
- "kind": "field",
848
- "name": "_onSystemThemeChange",
849
- "type": {
850
- "text": "(() => void) | null"
851
- },
852
- "privacy": "private",
853
- "default": "null"
854
- },
855
805
  {
856
806
  "kind": "method",
857
807
  "name": "firstUpdated",
@@ -879,21 +829,6 @@
879
829
  }
880
830
  ]
881
831
  },
882
- {
883
- "kind": "method",
884
- "name": "_isDark",
885
- "privacy": "private",
886
- "return": {
887
- "type": {
888
- "text": "boolean"
889
- }
890
- }
891
- },
892
- {
893
- "kind": "method",
894
- "name": "_observeTheme",
895
- "privacy": "private"
896
- },
897
832
  {
898
833
  "kind": "method",
899
834
  "name": "_createView",
@@ -940,7 +875,7 @@
940
875
  }
941
876
  },
942
877
  {
943
- "description": "Fires when the document content changes. `event.detail.value` contains the new content.",
878
+ "description": "Fires when the document content changes. Read the new content from the element’s `value` property.",
944
879
  "name": "sigvelo-change"
945
880
  }
946
881
  ],
@@ -950,7 +885,7 @@
950
885
  },
951
886
  "tagName": "sigvelo-code-editor",
952
887
  "customElement": true,
953
- "summary": "A CodeMirror 6 wrapper that provides syntax-highlighted editing for\na single document. Supports JavaScript, TypeScript, JSX, TSX, HTML, and CSS.\nAutomatically detects dark mode from the `data-theme` attribute on the\ndocument root and applies the One Dark CodeMirror theme accordingly."
888
+ "summary": "A CodeMirror 6 wrapper that provides syntax-highlighted editing for\na single document. Supports JavaScript, TypeScript, JSX, TSX, HTML, and CSS.\nUses the shared editor tokens, inheriting scoped `data-theme` overrides\nand the operating-system theme. Tab moves focus out of the editor."
954
889
  }
955
890
  ],
956
891
  "exports": [
@@ -1078,6 +1013,24 @@
1078
1013
  "privacy": "private",
1079
1014
  "default": "[]"
1080
1015
  },
1016
+ {
1017
+ "kind": "field",
1018
+ "name": "_runId",
1019
+ "type": {
1020
+ "text": "number"
1021
+ },
1022
+ "privacy": "private",
1023
+ "default": "0"
1024
+ },
1025
+ {
1026
+ "kind": "field",
1027
+ "name": "_hasRun",
1028
+ "type": {
1029
+ "text": "boolean"
1030
+ },
1031
+ "privacy": "private",
1032
+ "default": "false"
1033
+ },
1081
1034
  {
1082
1035
  "kind": "field",
1083
1036
  "name": "_pendingPyPayload",
@@ -1549,7 +1502,7 @@
1549
1502
  {
1550
1503
  "name": "changed",
1551
1504
  "type": {
1552
- "text": "PropertyValues",
1505
+ "text": "PropertyValues<this>",
1553
1506
  "references": [
1554
1507
  {
1555
1508
  "name": "PropertyValues",
@@ -1571,7 +1524,7 @@
1571
1524
  {
1572
1525
  "name": "changed",
1573
1526
  "type": {
1574
- "text": "PropertyValues",
1527
+ "text": "PropertyValues<this>",
1575
1528
  "references": [
1576
1529
  {
1577
1530
  "name": "PropertyValues",
@@ -1619,7 +1572,23 @@
1619
1572
  {
1620
1573
  "kind": "method",
1621
1574
  "name": "_initFiles",
1622
- "privacy": "private"
1575
+ "privacy": "private",
1576
+ "parameters": [
1577
+ {
1578
+ "name": "previousFiles",
1579
+ "default": "[]",
1580
+ "type": {
1581
+ "text": "EditorFile[]",
1582
+ "references": [
1583
+ {
1584
+ "name": "EditorFile",
1585
+ "start": 0,
1586
+ "end": 10
1587
+ }
1588
+ ]
1589
+ }
1590
+ }
1591
+ ]
1623
1592
  },
1624
1593
  {
1625
1594
  "kind": "method",
@@ -1701,6 +1670,27 @@
1701
1670
  "name": "_confirmAddFile",
1702
1671
  "privacy": "private"
1703
1672
  },
1673
+ {
1674
+ "kind": "method",
1675
+ "name": "_onNewFileNameInput",
1676
+ "privacy": "private",
1677
+ "parameters": [
1678
+ {
1679
+ "name": "e",
1680
+ "type": {
1681
+ "text": "Event",
1682
+ "references": [
1683
+ {
1684
+ "name": "Event",
1685
+ "package": "dom",
1686
+ "start": 0,
1687
+ "end": 5
1688
+ }
1689
+ ]
1690
+ }
1691
+ }
1692
+ ]
1693
+ },
1704
1694
  {
1705
1695
  "kind": "method",
1706
1696
  "name": "_dismissAddFile",
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as FileLanguage, s as detectLanguage, t as EditorFile } from "./transform-DWhHlnkw.js";
1
+ import { EditorFile, FileLanguage, detectLanguage } from "./lib/transform.js";
2
2
  import { SigveloCodeEditor } from "./components/code-editor/code-editor.js";
3
3
  import { SigveloCodePreview } from "./components/code-preview/code-preview.js";
4
4
  import { SigveloInteractiveEditor } from "./components/interactive-editor/interactive-editor.js";
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import { t as SigveloCodeEditor } from "./code-editor-B94tewLC.js";
1
+ import { t as SigveloCodeEditor } from "./code-editor-hnbxw8Xk.js";
2
2
  import { detectLanguage } from "./lib/transform.js";
3
3
  import { getRunnerUrl, setRunnerBaseUrl } from "./lib/runner-url.js";
4
- import { t as SigveloCodePreview } from "./code-preview-gKk0nBKP.js";
5
- import { t as SigveloInteractiveEditor } from "./interactive-editor-WfTWxJGF.js";
6
- import { t as SigveloREditor } from "./r-editor-DwSyDo2i.js";
7
- import { t as SigveloSqlEditor } from "./sql-editor-CsNrjJ2_.js";
4
+ import { t as SigveloCodePreview } from "./code-preview-Pq2CFfK9.js";
5
+ import { t as SigveloInteractiveEditor } from "./interactive-editor-DQfrcGUo.js";
6
+ import { t as SigveloREditor } from "./r-editor-BuoVoBdn.js";
7
+ import { t as SigveloSqlEditor } from "./sql-editor-26vbWzLE.js";
8
8
  export { SigveloCodeEditor, SigveloCodePreview, SigveloInteractiveEditor, SigveloREditor, SigveloSqlEditor, detectLanguage, getRunnerUrl, setRunnerBaseUrl };
@@ -1,7 +1,7 @@
1
- import "./code-editor-B94tewLC.js";
1
+ import { t as SigveloCodeEditor } from "./code-editor-hnbxw8Xk.js";
2
2
  import { t as __decorate } from "./decorate-DcF3lt7P.js";
3
3
  import { detectLanguage } from "./lib/transform.js";
4
- import "./code-preview-gKk0nBKP.js";
4
+ import "./code-preview-Pq2CFfK9.js";
5
5
  import { css, html } from "lit";
6
6
  import { property, query, state } from "lit/decorators.js";
7
7
  import { SigveloElement } from "@mcp-b/wc-support/base/sigvelo-element";
@@ -744,6 +744,7 @@ const FILE_DEFAULTS = {
744
744
  sql: "-- SQL\n"
745
745
  };
746
746
  const COMPACT_BREAKPOINT = 560;
747
+ const RUN_DEBOUNCE_MS = 800;
747
748
  const ICON_PLAY = html`
748
749
  <svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor" style="display: block">
749
750
  <path d="M5 3l14 9-14 9V3z" />
@@ -938,6 +939,7 @@ var SigveloInteractiveEditor = class extends SigveloElement {
938
939
  }
939
940
  });
940
941
  this._resizeObserver.observe(this);
942
+ if (this.hasUpdated) this._runCode(false);
941
943
  }
942
944
  disconnectedCallback() {
943
945
  super.disconnectedCallback();
@@ -946,7 +948,7 @@ var SigveloInteractiveEditor = class extends SigveloElement {
946
948
  }
947
949
  willUpdate(changed) {
948
950
  if (changed.has("files")) {
949
- this._initFiles();
951
+ this._initFiles(changed.get("files"));
950
952
  this._consoleLogs = [];
951
953
  this._unreadConsoleCount = 0;
952
954
  }
@@ -955,8 +957,7 @@ var SigveloInteractiveEditor = class extends SigveloElement {
955
957
  if (changed.has("files")) this._runCode(false);
956
958
  }
957
959
  _onConsoleMessage(e) {
958
- const entry = e.detail;
959
- this._consoleLogs = [...this._consoleLogs, entry];
960
+ this._consoleLogs = [...this._consoleLogs, e.detail].slice(-500);
960
961
  if (this._rightPane !== "console" && !this._compact) this._unreadConsoleCount++;
961
962
  if (this._compact && this._compactView !== "console") this._unreadConsoleCount++;
962
963
  }
@@ -964,12 +965,13 @@ var SigveloInteractiveEditor = class extends SigveloElement {
964
965
  this._consoleLogs = [];
965
966
  this._unreadConsoleCount = 0;
966
967
  }
967
- _initFiles() {
968
+ _initFiles(previousFiles = []) {
968
969
  const prev = this._fileContents;
970
+ const previousSources = new Map(previousFiles.map((file) => [file.name, file.content]));
969
971
  this._fileContents = /* @__PURE__ */ new Map();
970
972
  const folders = /* @__PURE__ */ new Set();
971
973
  for (const f of this.files) {
972
- this._fileContents.set(f.name, prev.get(f.name) ?? f.content);
974
+ this._fileContents.set(f.name, previousSources.get(f.name) === f.content ? prev.get(f.name) ?? f.content : f.content);
973
975
  const parts = f.name.split("/");
974
976
  for (let i = 1; i < parts.length; i++) folders.add(parts.slice(0, i).join("/"));
975
977
  }
@@ -983,18 +985,18 @@ var SigveloInteractiveEditor = class extends SigveloElement {
983
985
  return this.files.find((f) => f.name === this._activeFileName)?.language ?? detectLanguage(this._activeFileName);
984
986
  }
985
987
  _onEditorChange(e) {
986
- const value = e.target.value;
988
+ if (!(e.target instanceof SigveloCodeEditor)) return;
987
989
  this._fileContents = new Map(this._fileContents);
988
- this._fileContents.set(this._activeFileName, value);
990
+ this._fileContents.set(this._activeFileName, e.target.value);
989
991
  this._scheduleRun();
990
992
  }
991
993
  _scheduleRun() {
992
994
  if (!this.autoRun) return;
993
995
  if (this._runDebounce) clearTimeout(this._runDebounce);
994
- this._runDebounce = setTimeout(() => void this._runCode(), 800);
996
+ this._runDebounce = setTimeout(() => void this._runCode(), RUN_DEBOUNCE_MS);
995
997
  }
996
998
  async _runCode(clearConsole = true) {
997
- if (!this._preview) return;
999
+ if (!this.isConnected || !this._preview) return;
998
1000
  if (clearConsole) {
999
1001
  this._consoleLogs = [];
1000
1002
  this._unreadConsoleCount = 0;
@@ -1062,6 +1064,11 @@ var SigveloInteractiveEditor = class extends SigveloElement {
1062
1064
  this._dismissAddFile();
1063
1065
  this._activeFileName = name;
1064
1066
  }
1067
+ _onNewFileNameInput(e) {
1068
+ if (!(e.target instanceof HTMLInputElement)) return;
1069
+ this._newFileName = e.target.value;
1070
+ this._fileError = "";
1071
+ }
1065
1072
  _dismissAddFile() {
1066
1073
  this._showAddFile = false;
1067
1074
  this._newFileName = "";
@@ -1198,10 +1205,7 @@ var SigveloInteractiveEditor = class extends SigveloElement {
1198
1205
  placeholder="src/App.tsx"
1199
1206
  autofocus
1200
1207
  .value=${this._newFileName}
1201
- @input=${(e) => {
1202
- this._newFileName = e.target.value;
1203
- this._fileError = "";
1204
- }}
1208
+ @input=${this._onNewFileNameInput}
1205
1209
  @keydown=${(e) => {
1206
1210
  if (e.key === "Enter") this._confirmAddFile();
1207
1211
  if (e.key === "Escape") this._dismissAddFile();
@@ -1362,10 +1366,7 @@ var SigveloInteractiveEditor = class extends SigveloElement {
1362
1366
  type="text"
1363
1367
  placeholder="filename.ts"
1364
1368
  .value=${this._newFileName}
1365
- @input=${(e) => {
1366
- this._newFileName = e.target.value;
1367
- this._fileError = "";
1368
- }}
1369
+ @input=${this._onNewFileNameInput}
1369
1370
  @keydown=${(e) => {
1370
1371
  if (e.key === "Enter") this._confirmAddFile();
1371
1372
  if (e.key === "Escape") this._dismissAddFile();
@@ -1,2 +1,53 @@
1
- import { a as buildModulePreview, c as needsTransform, i as buildHtmlPreview, l as rewriteNpmImports, n as FileLanguage, o as buildPythonPayload, r as PyScriptRunPayload, s as detectLanguage, t as EditorFile, u as transformCode } from "../transform-DWhHlnkw.js";
1
+ //#region src/lib/transform.d.ts
2
+ /**
3
+ * In-browser code transformation and preview building.
4
+ *
5
+ * - esm.sh transform API for TS/TSX/JSX → ES module transpilation
6
+ * - Blob URLs for inter-file module resolution
7
+ * - Import rewriting for npm packages via esm.sh CDN
8
+ */
9
+ type FileLanguage = "javascript" | "typescript" | "jsx" | "tsx" | "html" | "css" | "python" | "r" | "sql";
10
+ interface EditorFile {
11
+ name: string;
12
+ content: string;
13
+ language?: FileLanguage;
14
+ }
15
+ declare function detectLanguage(filename: string): FileLanguage;
16
+ declare function needsTransform(lang: FileLanguage): boolean;
17
+ declare function transformCode(code: string, filename: string): Promise<string>;
18
+ /** Rewrites bare npm specifiers (`from 'react'`) to esm.sh CDN URLs. */
19
+ declare function rewriteNpmImports(code: string): string;
20
+ /**
21
+ * Builds a preview for HTML-entry projects. Inlines referenced CSS and JS
22
+ * files, transforming TS/JSX as needed.
23
+ */
24
+ declare function buildHtmlPreview(files: Map<string, EditorFile>): Promise<string>;
25
+ /**
26
+ * Builds a preview for module-entry projects (TS/TSX/JS). Transforms each
27
+ * file, creates Blob URLs for inter-file imports, and wraps in HTML.
28
+ *
29
+ * Returns `{ html, blobUrls }` — caller should revoke blob URLs on cleanup.
30
+ */
31
+ declare function buildModulePreview(files: Map<string, EditorFile>, entryName: string): Promise<{
32
+ html: string;
33
+ blobUrls: string[];
34
+ }>;
35
+ /** Payload sent to the pyscript-runner.html page via postMessage. */
36
+ interface PyScriptRunPayload {
37
+ type: "pyscript-run";
38
+ code: string;
39
+ bodyHtml: string;
40
+ css: string;
41
+ config: Record<string, unknown> | null;
42
+ }
43
+ /**
44
+ * Builds a postMessage payload for the PyScript runner page.
45
+ *
46
+ * PyScript cannot run inside srcdoc or blob-URL iframes because it uses
47
+ * `new URL(m, location.href)` internally, and those iframe types have
48
+ * invalid base URLs. Instead, we load a static `pyscript-runner.html`
49
+ * page (served at a real HTTP URL) and send code to it via postMessage.
50
+ */
51
+ declare function buildPythonPayload(files: Map<string, EditorFile>, entryName: string): PyScriptRunPayload;
52
+ //#endregion
2
53
  export { EditorFile, FileLanguage, PyScriptRunPayload, buildHtmlPreview, buildModulePreview, buildPythonPayload, detectLanguage, needsTransform, rewriteNpmImports, transformCode };
@@ -1,4 +1,12 @@
1
+ import { isRecord } from "./runner-channel.js";
1
2
  //#region src/lib/transform.ts
3
+ /**
4
+ * In-browser code transformation and preview building.
5
+ *
6
+ * - esm.sh transform API for TS/TSX/JSX → ES module transpilation
7
+ * - Blob URLs for inter-file module resolution
8
+ * - Import rewriting for npm packages via esm.sh CDN
9
+ */
2
10
  function detectLanguage(filename) {
3
11
  return {
4
12
  ts: "typescript",
@@ -32,7 +40,9 @@ async function transformCode(code, filename) {
32
40
  const text = await res.text();
33
41
  throw new Error(`esm.sh transform failed (${res.status}): ${text}`);
34
42
  }
35
- return (await res.json()).code;
43
+ const payload = await res.json();
44
+ if (!isRecord(payload) || typeof payload.code !== "string") throw new Error(`esm.sh transform returned an unexpected payload for ${filename}`);
45
+ return payload.code;
36
46
  }
37
47
  /** Rewrites bare npm specifiers (`from 'react'`) to esm.sh CDN URLs. */
38
48
  function rewriteNpmImports(code) {
@@ -104,25 +114,21 @@ async function buildModulePreview(files, entryName) {
104
114
  }
105
115
  const cssChunks = [];
106
116
  for (const [, file] of files) if ((file.language ?? detectLanguage(file.name)) === "css") cssChunks.push(file.content);
107
- const fileNames = [...transformed.keys()];
108
117
  const blobUrlMap = /* @__PURE__ */ new Map();
109
- for (const name of fileNames) {
110
- let code = transformed.get(name);
111
- code = patchRelativeImports(code, name, blobUrlMap);
112
- const blob = new Blob([code], { type: "text/javascript" });
118
+ for (const [name, source] of transformed) {
119
+ const blob = new Blob([patchRelativeImports(source, name, blobUrlMap)], { type: "text/javascript" });
113
120
  const url = URL.createObjectURL(blob);
114
121
  blobUrlMap.set(name, url);
115
122
  blobUrls.push(url);
116
123
  }
117
- if (fileNames.length > 1) {
118
- const entryUrl = blobUrlMap.get(entryName);
119
- if (entryUrl) {
120
- URL.revokeObjectURL(entryUrl);
121
- blobUrls.splice(blobUrls.indexOf(entryUrl), 1);
124
+ const entrySource = transformed.get(entryName);
125
+ if (entrySource !== void 0 && transformed.size > 1) {
126
+ const staleEntryUrl = blobUrlMap.get(entryName);
127
+ if (staleEntryUrl) {
128
+ URL.revokeObjectURL(staleEntryUrl);
129
+ blobUrls.splice(blobUrls.indexOf(staleEntryUrl), 1);
122
130
  }
123
- let code = transformed.get(entryName);
124
- code = patchRelativeImports(code, entryName, blobUrlMap);
125
- const blob = new Blob([code], { type: "text/javascript" });
131
+ const blob = new Blob([patchRelativeImports(entrySource, entryName, blobUrlMap)], { type: "text/javascript" });
126
132
  const url = URL.createObjectURL(blob);
127
133
  blobUrlMap.set(entryName, url);
128
134
  blobUrls.push(url);
@@ -163,7 +169,9 @@ function buildPythonPayload(files, entryName) {
163
169
  const jsonFile = files.get("pyscript.json");
164
170
  if (jsonFile) try {
165
171
  config = JSON.parse(jsonFile.content);
166
- } catch {}
172
+ } catch {
173
+ config = null;
174
+ }
167
175
  const htmlFile = files.get("index.html");
168
176
  const bodyHtml = htmlFile ? htmlFile.content.replace(/<!DOCTYPE[^>]*>/i, "").replace(/<\/?html[^>]*>/gi, "").replace(/<head[\s\S]*?<\/head>/i, "").replace(/<\/?body[^>]*>/gi, "") : "";
169
177
  return {
@@ -1,4 +1,4 @@
1
- import "./code-editor-B94tewLC.js";
1
+ import { t as SigveloCodeEditor } from "./code-editor-hnbxw8Xk.js";
2
2
  import { t as __decorate } from "./decorate-DcF3lt7P.js";
3
3
  import { bindRunnerUrl, connectRunner, createRunnerChannelId, isRecord, parseRunnerConsoleMessage } from "./lib/runner-channel.js";
4
4
  import { getRunnerUrl } from "./lib/runner-url.js";
@@ -416,7 +416,8 @@ var SigveloREditor = class extends SigveloElement {
416
416
  }
417
417
  connectedCallback() {
418
418
  super.connectedCallback();
419
- this._editedCode = this.code;
419
+ if (!this.hasUpdated) this._editedCode = this.code;
420
+ if (this.hasUpdated) this._initRunner();
420
421
  this._resizeObserver = new ResizeObserver((entries) => {
421
422
  for (const entry of entries) {
422
423
  const compact = entry.contentRect.width < COMPACT_BREAKPOINT;
@@ -437,10 +438,16 @@ var SigveloREditor = class extends SigveloElement {
437
438
  this._runnerIframe = null;
438
439
  }
439
440
  _initRunner() {
441
+ if (!this.isConnected || this._runnerIframe) return;
442
+ this._webRReady = false;
443
+ this._webRLoading = true;
444
+ this._loadingMessage = "Initializing WebR...";
445
+ this._running = false;
440
446
  const iframe = document.createElement("iframe");
441
447
  iframe.style.display = "none";
442
448
  iframe.sandbox.add("allow-scripts");
443
449
  iframe.addEventListener("load", () => {
450
+ if (!this.isConnected || this._runnerIframe !== iframe) return;
444
451
  this._runnerPort?.close();
445
452
  this._runnerPort = connectRunner(iframe, this._runnerChannelId, (data) => this._onMessage(data));
446
453
  }, { once: true });
@@ -464,8 +471,7 @@ var SigveloREditor = class extends SigveloElement {
464
471
  }
465
472
  const consoleMessage = parseRunnerConsoleMessage(data);
466
473
  if (consoleMessage) {
467
- const entry = consoleMessage;
468
- this._consoleLogs = [...this._consoleLogs, entry];
474
+ this._consoleLogs = [...this._consoleLogs, consoleMessage].slice(-500);
469
475
  if (!this._compact && this._rightPane !== "console") this._unreadConsoleCount++;
470
476
  if (this._compact && this._compactView !== "console") this._unreadConsoleCount++;
471
477
  return;
@@ -500,6 +506,7 @@ var SigveloREditor = class extends SigveloElement {
500
506
  });
501
507
  }
502
508
  _onEditorChange(e) {
509
+ if (!(e.target instanceof SigveloCodeEditor)) return;
503
510
  this._editedCode = e.target.value;
504
511
  }
505
512
  _prevPlot() {
@@ -1,4 +1,4 @@
1
- import "./code-editor-B94tewLC.js";
1
+ import { t as SigveloCodeEditor } from "./code-editor-hnbxw8Xk.js";
2
2
  import { t as __decorate } from "./decorate-DcF3lt7P.js";
3
3
  import { isRecord } from "./lib/runner-channel.js";
4
4
  import { getRunnerUrl } from "./lib/runner-url.js";
@@ -435,6 +435,15 @@ var sql_editor_styles_default = css`
435
435
  `;
436
436
  //#endregion
437
437
  //#region src/components/sql-editor/sql-editor.ts
438
+ function isResultField(value) {
439
+ return isRecord(value) && typeof value.name === "string" && typeof value.dataTypeID === "number";
440
+ }
441
+ function isSchemaColumn(value) {
442
+ return isRecord(value) && typeof value.name === "string" && typeof value.type === "string" && typeof value.nullable === "boolean";
443
+ }
444
+ function isSchemaTable(value) {
445
+ return isRecord(value) && typeof value.name === "string" && Array.isArray(value.columns) && value.columns.every(isSchemaColumn);
446
+ }
438
447
  const ICON_PLAY = html`
439
448
  <svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor" style="display: block">
440
449
  <path d="M5 3l14 9-14 9V3z" />
@@ -483,8 +492,9 @@ const MAX_DISPLAY_ROWS = 1e3;
483
492
  function formatCell(value) {
484
493
  if (value === null || value === void 0) return "";
485
494
  if (typeof value === "string") return value;
486
- if (typeof value === "object") return JSON.stringify(value) ?? "";
487
- return typeof value === "symbol" ? value.toString() : `${value}`;
495
+ if (typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") return String(value);
496
+ if (typeof value === "symbol") return value.toString();
497
+ return JSON.stringify(value) ?? "";
488
498
  }
489
499
  /**
490
500
  * `<sigvelo-sql-editor>`
@@ -533,7 +543,8 @@ var SigveloSqlEditor = class extends SigveloElement {
533
543
  }
534
544
  connectedCallback() {
535
545
  super.connectedCallback();
536
- this._editedCode = this.code;
546
+ if (!this.hasUpdated) this._editedCode = this.code;
547
+ if (this.hasUpdated) this._initRunner();
537
548
  this._resizeObserver = new ResizeObserver((entries) => {
538
549
  for (const entry of entries) {
539
550
  const compact = entry.contentRect.width < COMPACT_BREAKPOINT;
@@ -554,14 +565,20 @@ var SigveloSqlEditor = class extends SigveloElement {
554
565
  this._runner = null;
555
566
  }
556
567
  _initRunner() {
568
+ if (!this.isConnected || this._runner) return;
569
+ this._pgliteReady = false;
570
+ this._pgliteLoading = true;
571
+ this._loadingMessage = "Initializing PostgreSQL...";
572
+ this._running = false;
557
573
  const runner = new Worker(getRunnerUrl("pglite"), {
558
574
  name: "sigvelo-pglite",
559
575
  type: "module"
560
576
  });
561
577
  runner.addEventListener("message", (event) => {
562
- this._onMessage(event.data);
578
+ if (this._runner === runner && this.isConnected) this._onMessage(event.data);
563
579
  });
564
580
  runner.addEventListener("error", (event) => {
581
+ if (this._runner !== runner || !this.isConnected) return;
565
582
  this._pgliteLoading = false;
566
583
  this._error = event.message || "PostgreSQL runner failed to load";
567
584
  });
@@ -597,7 +614,7 @@ var SigveloSqlEditor = class extends SigveloElement {
597
614
  this._requestSchema();
598
615
  return;
599
616
  }
600
- if (data.__sigvelo_pglite_result === true && Array.isArray(data.fields) && data.fields.every((field) => isRecord(field) && typeof field.name === "string" && typeof field.dataTypeID === "number") && Array.isArray(data.rows) && data.rows.every(isRecord) && typeof data.rowCount === "number" && typeof data.executionTimeMs === "number") {
617
+ if (data.__sigvelo_pglite_result === true && Array.isArray(data.fields) && data.fields.every(isResultField) && Array.isArray(data.rows) && data.rows.every(isRecord) && typeof data.rowCount === "number" && typeof data.executionTimeMs === "number") {
601
618
  this._resultFields = data.fields;
602
619
  this._resultRows = data.rows;
603
620
  this._rowCount = data.rowCount;
@@ -620,7 +637,7 @@ var SigveloSqlEditor = class extends SigveloElement {
620
637
  this._pgliteLoading = false;
621
638
  return;
622
639
  }
623
- if (data.__sigvelo_pglite_schema === true && Array.isArray(data.tables) && data.tables.every((table) => isRecord(table) && typeof table.name === "string" && Array.isArray(table.columns) && table.columns.every((column) => isRecord(column) && typeof column.name === "string" && typeof column.type === "string" && typeof column.nullable === "boolean"))) {
640
+ if (data.__sigvelo_pglite_schema === true && Array.isArray(data.tables) && data.tables.every(isSchemaTable)) {
624
641
  this._schema = data.tables;
625
642
  if (this._expandedTables.size === 0) this._expandedTables = new Set(this._schema.map((t) => t.name));
626
643
  return;
@@ -655,6 +672,7 @@ var SigveloSqlEditor = class extends SigveloElement {
655
672
  });
656
673
  }
657
674
  _onEditorChange(e) {
675
+ if (!(e.target instanceof SigveloCodeEditor)) return;
658
676
  this._editedCode = e.target.value;
659
677
  }
660
678
  _resetDatabase() {
@@ -14,11 +14,12 @@
14
14
  * surface stays even.
15
15
  */
16
16
 
17
- :root {
18
- /* Structure: derived, so the editor sits on the same surfaces as CodeBlock. */
19
- --sigvelo-interactive-editor-bg: var(--sigvelo-color-neutral-bg-subtle);
17
+ :root,
18
+ [data-theme] {
19
+ /* An opaque surface keeps nested editor layers from compounding alpha and reducing contrast. */
20
+ --sigvelo-interactive-editor-bg: var(--sigvelo-color-surface-sunken);
20
21
  --sigvelo-interactive-editor-gutter-bg: transparent;
21
- --sigvelo-interactive-editor-gutter-text: var(--sigvelo-color-text-faint);
22
+ --sigvelo-interactive-editor-gutter-text: var(--sigvelo-color-text-muted);
22
23
  --sigvelo-interactive-editor-selection: var(--sigvelo-color-primary-bg-muted);
23
24
  --sigvelo-interactive-editor-active-line: var(--sigvelo-color-neutral-bg-muted);
24
25
  --sigvelo-interactive-editor-cursor: var(--sigvelo-color-text);
@@ -28,13 +29,13 @@
28
29
  /* Syntax hues, light. */
29
30
  --sigvelo-interactive-syn-keyword: #a032a8;
30
31
  --sigvelo-interactive-syn-string: #0a6640;
31
- --sigvelo-interactive-syn-comment: var(--sigvelo-color-text-subtle);
32
- --sigvelo-interactive-syn-number: #7c4dff;
32
+ --sigvelo-interactive-syn-comment: var(--sigvelo-color-text-muted);
33
+ --sigvelo-interactive-syn-number: #663dcc;
33
34
  --sigvelo-interactive-syn-function: #0550ae;
34
- --sigvelo-interactive-syn-variable: #b3541e;
35
+ --sigvelo-interactive-syn-variable: #934615;
35
36
  --sigvelo-interactive-syn-type: #0550ae;
36
37
  --sigvelo-interactive-syn-tag: #0a6640;
37
- --sigvelo-interactive-syn-attribute: #b3541e;
38
+ --sigvelo-interactive-syn-attribute: #934615;
38
39
  --sigvelo-interactive-syn-property: #0550ae;
39
40
  --sigvelo-interactive-syn-punctuation: var(--sigvelo-color-text-muted);
40
41
  }
@@ -57,12 +58,12 @@
57
58
  [data-theme="light"] {
58
59
  --sigvelo-interactive-syn-keyword: #a032a8;
59
60
  --sigvelo-interactive-syn-string: #0a6640;
60
- --sigvelo-interactive-syn-number: #7c4dff;
61
+ --sigvelo-interactive-syn-number: #663dcc;
61
62
  --sigvelo-interactive-syn-function: #0550ae;
62
- --sigvelo-interactive-syn-variable: #b3541e;
63
+ --sigvelo-interactive-syn-variable: #934615;
63
64
  --sigvelo-interactive-syn-type: #0550ae;
64
65
  --sigvelo-interactive-syn-tag: #0a6640;
65
- --sigvelo-interactive-syn-attribute: #b3541e;
66
+ --sigvelo-interactive-syn-attribute: #934615;
66
67
  --sigvelo-interactive-syn-property: #0550ae;
67
68
  }
68
69