@marimo-team/islands 0.23.14-dev17 → 0.23.14-dev19

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.
@@ -1,6 +1,6 @@
1
1
  import { s as __toESM } from "./chunk-BNovOVIE.js";
2
2
  import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
3
- import { at as parseHtmlContent, it as ansiToPlainText } from "./html-to-image-DcTkcjmm.js";
3
+ import { at as parseHtmlContent, it as ansiToPlainText } from "./html-to-image-DBHfshED.js";
4
4
  import { u as createLucideIcon } from "./dist--2Bqjvs0.js";
5
5
  import { t as Strings } from "./strings-Dq_j3Rxw.js";
6
6
  import { t as require_jsx_runtime } from "./jsx-runtime-DebpN0FN.js";
@@ -6,10 +6,10 @@ import { s as __toESM } from "./chunk-BNovOVIE.js";
6
6
  import { _ as Logger, g as cn, h as Events, l as useEventListener, t as Button } from "./button-BacYv-bE.js";
7
7
  import { t as require_react } from "./react-DA-nE2FX.js";
8
8
  import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
9
- import { lt as kioskModeAtom } from "./html-to-image-DcTkcjmm.js";
9
+ import { lt as kioskModeAtom } from "./html-to-image-DBHfshED.js";
10
10
  import "./chunk-5FQGJX7Z-BbqSm5gU.js";
11
11
  import { u as createLucideIcon } from "./dist--2Bqjvs0.js";
12
- import { a as DEFAULT_SLIDE_TYPE, c as Slide, ct as PanelGroup, i as DEFAULT_DECK_TRANSITION, lt as PanelResizeHandle, on as EyeOff, s as SlideSidebar, sn as Expand, st as Panel, t as useNotebookCodeAvailable, un as Code } from "./code-visibility-Cb6UrZYv.js";
12
+ import { a as DEFAULT_SLIDE_TYPE, c as Slide, ct as PanelGroup, i as DEFAULT_DECK_TRANSITION, lt as PanelResizeHandle, on as EyeOff, s as SlideSidebar, sn as Expand, st as Panel, t as useNotebookCodeAvailable, un as Code } from "./code-visibility-CxDvzm2S.js";
13
13
  import { X as useDebouncedCallback } from "./input-BSdZp5Ng.js";
14
14
  import "./toDate-D1Z7ZXWh.js";
15
15
  import "./react-dom-BTJzcVJ9.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.23.14-dev17",
3
+ "version": "0.23.14-dev19",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -31,7 +31,7 @@ import { cn } from "@/utils/cn";
31
31
  import { HideInKioskMode } from "../../kiosk-mode";
32
32
  import { ContributeSnippetButton } from "../components/contribute-snippet-button";
33
33
  import { usePanelOrientation, usePanelSection } from "./panel-context";
34
- import { getSnippetDisplay } from "./snippet-display";
34
+ import { getReadonlyCodeDisplay } from "@/core/cells/readonly-code-display";
35
35
 
36
36
  const extensions = [EditorView.lineWrapping];
37
37
 
@@ -188,7 +188,7 @@ const SnippetViewer: React.FC<{ snippet: Snippet; onClose: () => void }> = ({
188
188
  return null;
189
189
  }
190
190
 
191
- const { language, value } = getSnippetDisplay(code);
191
+ const { language, code: displayCode } = getReadonlyCodeDisplay(code);
192
192
 
193
193
  return (
194
194
  <div
@@ -216,7 +216,7 @@ const SnippetViewer: React.FC<{ snippet: Snippet; onClose: () => void }> = ({
216
216
  language={language}
217
217
  className="cm border rounded overflow-hidden"
218
218
  extensions={extensions}
219
- value={value}
219
+ value={displayCode}
220
220
  readOnly={true}
221
221
  />
222
222
  </Suspense>
@@ -1,5 +1,6 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
+ import { markdown } from "@codemirror/lang-markdown";
3
4
  import { sql } from "@codemirror/lang-sql";
4
5
  import CodeMirror, {
5
6
  EditorView,
@@ -11,6 +12,7 @@ import { useAddCodeToNewCell } from "@/components/editor/cell/useAddCell";
11
12
  import { Button } from "@/components/ui/button";
12
13
  import { Tooltip } from "@/components/ui/tooltip";
13
14
  import { toast } from "@/components/ui/use-toast";
15
+ import type { LanguageAdapterType } from "@/core/codemirror/language/types";
14
16
  import { customPythonLanguageSupport } from "@/core/codemirror/language/languages/python";
15
17
  import { useTheme } from "@/theme/useTheme";
16
18
  import { cn } from "@/utils/cn";
@@ -22,6 +24,18 @@ const pythonExtensions = [
22
24
  EditorView.lineWrapping,
23
25
  ];
24
26
  const sqlExtensions = [sql(), EditorView.lineWrapping];
27
+ const markdownExtensions = [markdown(), EditorView.lineWrapping];
28
+
29
+ function readonlyCodeExtensions(language: LanguageAdapterType) {
30
+ switch (language) {
31
+ case "sql":
32
+ return sqlExtensions;
33
+ case "markdown":
34
+ return markdownExtensions;
35
+ default:
36
+ return pythonExtensions;
37
+ }
38
+ }
25
39
 
26
40
  /**
27
41
  * A readonly code component that can be used to display code in a readonly state.
@@ -42,7 +56,7 @@ export const ReadonlyCode = memo(
42
56
  showHideCode?: boolean;
43
57
  showCopyCode?: boolean;
44
58
  insertNewCell?: boolean;
45
- language?: "python" | "sql";
59
+ language?: LanguageAdapterType;
46
60
  } & ReactCodeMirrorProps,
47
61
  ) => {
48
62
  const { theme } = useTheme();
@@ -84,7 +98,7 @@ export const ReadonlyCode = memo(
84
98
  theme={theme === "dark" ? "dark" : "light"}
85
99
  height="100%"
86
100
  editable={!hideCode}
87
- extensions={language === "python" ? pythonExtensions : sqlExtensions}
101
+ extensions={readonlyCodeExtensions(language)}
88
102
  value={code}
89
103
  readOnly={true}
90
104
  />
@@ -2,11 +2,7 @@
2
2
  /* oxlint-disable typescript/no-explicit-any */
3
3
  import { describe, expect, it } from "vitest";
4
4
  import type { OutputMessage } from "@/core/kernel/messages";
5
- import {
6
- groupCellsByColumn,
7
- readonlyDisplay,
8
- shouldHideCode,
9
- } from "../vertical-layout";
5
+ import { groupCellsByColumn, shouldHideCode } from "../vertical-layout";
10
6
 
11
7
  describe("groupCellsByColumn", () => {
12
8
  it("should group cells by column and maintain order", () => {
@@ -175,25 +171,3 @@ describe("shouldHideCode", () => {
175
171
  });
176
172
  });
177
173
  });
178
-
179
- describe("readonlyDisplay", () => {
180
- it("unwraps SQL cells to their inner query and marks them as sql", () => {
181
- const result = readonlyDisplay('my_table = mo.sql("""SELECT 1 AS id""")');
182
- expect(result.language).toBe("sql");
183
- expect(result.code).toBe("SELECT 1 AS id");
184
- });
185
-
186
- it("leaves plain Python cells untouched", () => {
187
- const code = "x = 1 + 2";
188
- const result = readonlyDisplay(code);
189
- expect(result.language).toBe("python");
190
- expect(result.code).toBe(code);
191
- });
192
-
193
- it("leaves non-SQL cells (e.g. markdown) unchanged as python", () => {
194
- const code = 'mo.md("""## Heading""")';
195
- const result = readonlyDisplay(code);
196
- expect(result.language).toBe("python");
197
- expect(result.code).toBe(code);
198
- });
199
- });
@@ -10,7 +10,6 @@ import {
10
10
  Loader2Icon,
11
11
  MoreHorizontalIcon,
12
12
  } from "lucide-react";
13
- import { SQLParser } from "@marimo-team/smart-cells";
14
13
  import type React from "react";
15
14
  import { memo, useRef, useState } from "react";
16
15
  import { z } from "zod";
@@ -30,6 +29,7 @@ import { outputIsLoading, outputIsStale } from "@/core/cells/cell";
30
29
  import type { CellId } from "@/core/cells/ids";
31
30
  import { isOutputEmpty } from "@/core/cells/outputs";
32
31
  import type { CellData, CellRuntimeState } from "@/core/cells/types";
32
+ import { getReadonlyCodeDisplay } from "@/core/cells/readonly-code-display";
33
33
  import { MarkdownLanguageAdapter } from "@/core/codemirror/language/languages/markdown";
34
34
  import { useResolvedMarimoConfig } from "@/core/config/config";
35
35
  import { CSSClasses, KnownQueryParams } from "@/core/constants";
@@ -386,7 +386,7 @@ const VerticalCell = memo(
386
386
  // Hide the code if it's pure markdown and there's an output, or if the code is empty
387
387
  const hideCode = shouldHideCode(code, output);
388
388
  // Only unwrap SQL when the code will actually be rendered.
389
- const display = hideCode ? null : readonlyDisplay(code);
389
+ const display = hideCode ? null : getReadonlyCodeDisplay(code);
390
390
 
391
391
  return (
392
392
  <div
@@ -500,20 +500,3 @@ export function shouldHideCode(code: string, output: OutputMessage | null) {
500
500
  const hasOutput = output !== null && !isOutputEmpty(output);
501
501
  return (isPureMarkdown && hasOutput) || code.trim() === "";
502
502
  }
503
-
504
- const sqlParser = new SQLParser();
505
-
506
- /**
507
- * Unwrap SQL cells to their inner query so read-only views highlight them as
508
- * SQL instead of showing the raw `mo.sql(...)` wrapper.
509
- */
510
- export function readonlyDisplay(code: string): {
511
- code: string;
512
- language: "python" | "sql";
513
- } {
514
- const trimmed = code.trim();
515
- if (sqlParser.isSupported(trimmed)) {
516
- return { code: sqlParser.transformIn(trimmed).code, language: "sql" };
517
- }
518
- return { code, language: "python" };
519
- }
@@ -26,7 +26,7 @@ import { connectionAtom } from "@/core/network/connection";
26
26
  import { useTheme } from "@/theme/useTheme";
27
27
  import { cn } from "@/utils/cn";
28
28
  import { ReadonlyCode } from "../editor/code/readonly-python-code";
29
- import { languageAdapterFromCode } from "@/core/codemirror/language/extension";
29
+ import { getReadonlyCodeDisplay } from "@/core/cells/readonly-code-display";
30
30
 
31
31
  type RuntimeCell = CellRuntimeState & CellData;
32
32
 
@@ -188,10 +188,7 @@ export const SlideCellReadOnlyView = ({ cell }: { cell: RuntimeCell }) => {
188
188
  const [userConfig] = useUserConfig();
189
189
  const cellOutputPosition = userConfig.display.cell_output;
190
190
 
191
- const language = useMemo(() => {
192
- const adapter = languageAdapterFromCode(cell.code.trim());
193
- return adapter.type === "sql" ? "sql" : "python";
194
- }, [cell.code]);
191
+ const display = useMemo(() => getReadonlyCodeDisplay(cell.code), [cell.code]);
195
192
 
196
193
  const output = (
197
194
  <CellOutputSlide
@@ -203,7 +200,11 @@ export const SlideCellReadOnlyView = ({ cell }: { cell: RuntimeCell }) => {
203
200
 
204
201
  const editor = (
205
202
  <div className="marimo-cell">
206
- <ReadonlyCode code={cell.code} language={language} showHideCode={false} />
203
+ <ReadonlyCode
204
+ code={display.code}
205
+ language={display.language}
206
+ showHideCode={false}
207
+ />
207
208
  </div>
208
209
  );
209
210
 
@@ -0,0 +1,46 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { describe, expect, it } from "vitest";
4
+ import { getReadonlyCodeDisplay } from "../readonly-code-display";
5
+
6
+ describe("getReadonlyCodeDisplay", () => {
7
+ it("unwraps SQL cells to their inner query and marks them as sql", () => {
8
+ const result = getReadonlyCodeDisplay(
9
+ 'my_table = mo.sql("""SELECT 1 AS id""")',
10
+ );
11
+ expect(result.language).toBe("sql");
12
+ expect(result.code).toBe("SELECT 1 AS id");
13
+ });
14
+
15
+ it("unwraps f-string SQL cells", () => {
16
+ const result = getReadonlyCodeDisplay(
17
+ 'my_table = mo.sql(f"""SELECT 1 AS id""")',
18
+ );
19
+ expect(result.language).toBe("sql");
20
+ expect(result.code).toBe("SELECT 1 AS id");
21
+ });
22
+
23
+ it("leaves plain Python cells untouched", () => {
24
+ const code = "x = 1 + 2\nprint(x)";
25
+ const result = getReadonlyCodeDisplay(code);
26
+ expect(result.language).toBe("python");
27
+ expect(result.code).toBe(code);
28
+ });
29
+
30
+ it("unwraps markdown cells to their inner content", () => {
31
+ const result = getReadonlyCodeDisplay('mo.md("""## Heading""")');
32
+ expect(result.language).toBe("markdown");
33
+ expect(result.code).toBe("## Heading");
34
+ });
35
+
36
+ it("treats empty or whitespace-only code as python", () => {
37
+ expect(getReadonlyCodeDisplay("")).toEqual({
38
+ code: "",
39
+ language: "python",
40
+ });
41
+ expect(getReadonlyCodeDisplay(" \n\t ")).toEqual({
42
+ code: " \n\t ",
43
+ language: "python",
44
+ });
45
+ });
46
+ });
@@ -0,0 +1,35 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { MarkdownParser, SQLParser } from "@marimo-team/smart-cells";
4
+ import type { LanguageAdapterType } from "@/core/codemirror/language/types";
5
+
6
+ export interface ReadonlyCodeDisplay {
7
+ code: string;
8
+ language: LanguageAdapterType;
9
+ }
10
+
11
+ const markdownParser = new MarkdownParser();
12
+ const sqlParser = new SQLParser();
13
+
14
+ /**
15
+ * Unwrap SQL and markdown cells so read-only views show inner content with the
16
+ * correct syntax highlighting instead of the raw Python wrapper.
17
+ */
18
+ export function getReadonlyCodeDisplay(code: string): ReadonlyCodeDisplay {
19
+ const trimmed = code.trim();
20
+ if (!trimmed) {
21
+ return { code, language: "python" };
22
+ }
23
+
24
+ if (markdownParser.isSupported(trimmed)) {
25
+ return {
26
+ code: markdownParser.transformIn(trimmed).code,
27
+ language: "markdown",
28
+ };
29
+ }
30
+
31
+ if (sqlParser.isSupported(trimmed)) {
32
+ return { code: sqlParser.transformIn(trimmed).code, language: "sql" };
33
+ }
34
+ return { code, language: "python" };
35
+ }
@@ -1,22 +0,0 @@
1
- /* Copyright 2026 Marimo. All rights reserved. */
2
-
3
- import { describe, expect, it } from "vitest";
4
- import { getSnippetDisplay } from "../snippet-display";
5
-
6
- describe("getSnippetDisplay", () => {
7
- it("shows sql cells as the sql query", () => {
8
- const { language, value } = getSnippetDisplay(
9
- 'df = mo.sql("""SELECT * FROM users LIMIT 5""")',
10
- );
11
- expect(language).toBe("sql");
12
- expect(value).toBe("SELECT * FROM users LIMIT 5");
13
- });
14
-
15
- it("keeps plain python cells as python", () => {
16
- const code = "x = 1 + 2\nprint(x)";
17
- expect(getSnippetDisplay(code)).toEqual({
18
- language: "python",
19
- value: code,
20
- });
21
- });
22
- });
@@ -1,27 +0,0 @@
1
- /* Copyright 2026 Marimo. All rights reserved. */
2
-
3
- import { SQLParser } from "@marimo-team/smart-cells";
4
-
5
- export type SnippetLanguage = "python" | "sql";
6
-
7
- export interface SnippetDisplay {
8
- language: SnippetLanguage;
9
- value: string;
10
- }
11
-
12
- const sqlParser = new SQLParser();
13
-
14
- /**
15
- * Decide how a snippet's code should be shown in the panel.
16
- *
17
- * SQL cells are stored as python `mo.sql(...)`. Unwrap the inner query and
18
- * highlight it as SQL, matching how the cell renders once the snippet is
19
- * inserted. Everything else stays python.
20
- */
21
- export function getSnippetDisplay(code: string): SnippetDisplay {
22
- if (sqlParser.isSupported(code)) {
23
- const { code: query } = sqlParser.transformIn(code);
24
- return { language: "sql", value: query };
25
- }
26
- return { language: "python", value: code };
27
- }