@marimo-team/islands 0.25.3-dev322 → 0.25.3-dev348
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/dist/{ConnectedDataExplorerComponent-DkXBUBf3.js → ConnectedDataExplorerComponent-xliyyXNO.js} +16 -16
- package/dist/{ErrorBoundary-CYa6lyKz.js → ErrorBoundary-CIimOpqs.js} +7 -7
- package/dist/{abnfDiagram-VCTEODGH-BPS-pTU2.js → abnfDiagram-VCTEODGH-Dl9Nrtbf.js} +2 -2
- package/dist/{any-language-editor-DIS7IdV1.js → any-language-editor-CBHhdCC0.js} +2 -2
- package/dist/{architectureDiagram-5GKGNRK7-DB2MHOb7.js → architectureDiagram-5GKGNRK7-DTg032fQ.js} +1 -1
- package/dist/{assertNever-HbUt8DyH.js → assertNever-ie77PjMn.js} +13 -13
- package/dist/{chat-ui-85k50jaj.js → chat-ui-BV0qyfru.js} +51 -51
- package/dist/{check-CApDh1-n.js → check-DTIv5ZZ3.js} +1 -1
- package/dist/{chunk-IMKFNOWR-CjFCedjx.js → chunk-IMKFNOWR-CsFB-2LW.js} +1 -1
- package/dist/{chunk-SHT3W25Y-Dptltg0_.js → chunk-SHT3W25Y-ByuJHeBL.js} +1 -1
- package/dist/{chunk-SVP7TREG-2jBN760m.js → chunk-SVP7TREG-9oBZhbrr.js} +1 -1
- package/dist/{chunk-TICWLB2K-CS8BE-b9.js → chunk-TICWLB2K-Bx4m0cJ1.js} +1 -1
- package/dist/{classDiagram-ZZMXUADV-HtQWp-Cm.js → classDiagram-ZZMXUADV-Cms37-C9.js} +2 -2
- package/dist/{classDiagram-v2-VYDZK3BY-DA9LETN-.js → classDiagram-v2-VYDZK3BY-qAom4Bi7.js} +2 -2
- package/dist/{code-visibility-CGcIJMGj.js → code-visibility-_-8-dvb4.js} +20 -20
- package/dist/{common-B-Ng3J3K.js → common-CNXuhphD.js} +620 -620
- package/dist/{config-B171m9zn.js → config-CvBnR945.js} +3 -3
- package/dist/{copy-icon-k2_Fx5Qv.js → copy-icon-DmtNidSa.js} +2 -2
- package/dist/{createReducer-BPPI11pP.js → createReducer-BxBCTvKn.js} +5 -5
- package/dist/{cynefinDiagram-5FMLGOSQ-eyocrg_E.js → cynefinDiagram-5FMLGOSQ-BjJZwMEz.js} +1 -1
- package/dist/{dagre-GXQ25YYZ-Dtm96Nvx.js → dagre-GXQ25YYZ-Bohu7_09.js} +1 -1
- package/dist/{data-grid-overlay-editor-CUD6F0Vj.js → data-grid-overlay-editor--4Gk_rwA.js} +1 -1
- package/dist/{diagram-S7CK7UJ4-C09TrdNO.js → diagram-S7CK7UJ4-Chl0n835.js} +1 -1
- package/dist/{diagram-UQ7AKVKN-vHUsSML6.js → diagram-UQ7AKVKN-DHx8nzy7.js} +1 -1
- package/dist/{diagram-VX7I27RA-Ch4mRgz8.js → diagram-VX7I27RA-CKdpv1U4.js} +1 -1
- package/dist/{diagram-Z3DM3KII-DyFQNdAL.js → diagram-Z3DM3KII-sY-sI--2.js} +1 -1
- package/dist/{dialog-C2Muh059.js → dialog-Cqu5Hp5U.js} +21 -21
- package/dist/{dropdown-menu-BGbNnuFq.js → dropdown-menu-DXEYk99S.js} +707 -707
- package/dist/{ebnfDiagram-PWID7BFC-N3SvlrCs.js → ebnfDiagram-PWID7BFC-CD0P2xeH.js} +2 -2
- package/dist/{erDiagram-RLTQ6QDP-RR2q2xtd.js → erDiagram-RLTQ6QDP-BaKQuYxC.js} +1 -1
- package/dist/{error-banner-3_4Lc93Y.js → error-banner-DUB_qUeL.js} +58 -58
- package/dist/{error-entries-BhNAZWU1.js → error-entries-CTb_cxXY.js} +310 -310
- package/dist/{feedback-button-DK6zUzAk.js → feedback-button-BaA4r2dl.js} +7 -7
- package/dist/{flowDiagram-HODETNUW-nxd7WhlW.js → flowDiagram-HODETNUW-BcCpHh7-.js} +2 -2
- package/dist/{formats-aUcw6MrS.js → formats-hF6fETr6.js} +1 -1
- package/dist/{glide-data-editor-O-94UN5R.js → glide-data-editor-CRn3KXyR.js} +3129 -3119
- package/dist/{glide-utils-D4UP8TGv.js → glide-utils-Bnd_k48H.js} +2 -2
- package/dist/{globals-BVjYePCn.js → globals-_FmD97Ui.js} +3 -3
- package/dist/{html-to-image-DOOtP-4-.js → html-to-image-Bbl0PeC7.js} +478 -478
- package/dist/{infoDiagram-27XIBGKW-CUYXQKGf.js → infoDiagram-27XIBGKW-DWltseIa.js} +1 -1
- package/dist/{ishikawaDiagram-5VMMS53U-v6gsCrlK.js → ishikawaDiagram-5VMMS53U-DHgepBPo.js} +1 -1
- package/dist/{kanban-definition-UXKFOSKX-z236-0Ok.js → kanban-definition-UXKFOSKX-B2_BIjBq.js} +1 -1
- package/dist/main.js +6712 -6590
- package/dist/{mermaid-C7lQ_2LJ.js → mermaid--2K0cmt9.js} +34 -34
- package/dist/{mindmap-definition-YA3MSWOX--pZF7OCY.js → mindmap-definition-YA3MSWOX-DNebycIP.js} +1 -1
- package/dist/{number-overlay-editor-jkzzCN4e.js → number-overlay-editor-Bcg25qrp.js} +1 -1
- package/dist/{pegDiagram-XKGWAZYB-Bgw0Zz_6.js → pegDiagram-XKGWAZYB-CH4U3II-.js} +2 -2
- package/dist/{pencil-RXFY-Ek8.js → pencil-MMnw1YQh.js} +1 -1
- package/dist/{pieDiagram-E7YTZNPT-B27tDYvK.js → pieDiagram-E7YTZNPT-pfcrdUCa.js} +1 -1
- package/dist/{process-output-CiX_Dl4L.js → process-output-Dw_sI4Xp.js} +4 -4
- package/dist/{railroadDiagram-O6MQD6OU-CBjPhGpj.js → railroadDiagram-O6MQD6OU-BZKpAbNG.js} +2 -2
- package/dist/{requirementDiagram-BXWQKSXE-DDDrLEw9.js → requirementDiagram-BXWQKSXE-DnyfIHe3.js} +1 -1
- package/dist/{reveal-component-CvPmNI5C.js → reveal-component-BVC491am.js} +18 -18
- package/dist/{select-Cv6lR39D.js → select-suaAxFuo.js} +286 -286
- package/dist/{sequenceDiagram-WJ2MYXX4-DQPaMygQ.js → sequenceDiagram-WJ2MYXX4-BeYuWX7N.js} +1 -1
- package/dist/{spec-BoCLWa-M.js → spec-BQNx2-D7.js} +4 -4
- package/dist/{stateDiagram-D77RDMKH-BDoDVVnq.js → stateDiagram-D77RDMKH-B8FxwAM2.js} +2 -2
- package/dist/{stateDiagram-v2-MP3YSRHH-KNko46uJ.js → stateDiagram-v2-MP3YSRHH-CzWLBqm1.js} +2 -2
- package/dist/{static-state-DgdOadIH.js → static-state-Al_hmf1n.js} +6 -6
- package/dist/style.css +1 -1
- package/dist/{swimlanes-42K2YHIH-boFjOuiI.js → swimlanes-42K2YHIH-CzKmGMts.js} +1 -1
- package/dist/{swimlanesDiagram-VR7AAH4N-BC4FLNwY.js → swimlanesDiagram-VR7AAH4N-DnWIUN_9.js} +2 -2
- package/dist/{timeline-definition-24CTP7MA-CLVPYA-v.js → timeline-definition-24CTP7MA-Czf2QN2R.js} +1 -1
- package/dist/{toast-CUuX7uXg.js → toast-CsJa1nGj.js} +66 -66
- package/dist/{tooltip-DBv8QUvS.js → tooltip-BVbJPkcl.js} +49 -49
- package/dist/{use-restore-focus-BxJh5Zfa.js → use-restore-focus-tPmARo1Q.js} +1035 -1022
- package/dist/{useDateFormatter-2k4mHRBq.js → useDateFormatter-B4ygYuUU.js} +2 -2
- package/dist/{useDeepCompareMemoize-Cb2GRQIS.js → useDeepCompareMemoize-Bcu0DkCS.js} +1 -1
- package/dist/{useLifecycle-B2fV3c8N.js → useLifecycle-MTdtnR3-.js} +1 -1
- package/dist/{vega-component-do3stf0K.js → vega-component-BhBbP4S7.js} +6 -6
- package/dist/{vennDiagram-4TSXK5OY-BLq7sNjb.js → vennDiagram-4TSXK5OY-BrHqWB1U.js} +1 -1
- package/dist/{wardleyDiagram-VM6X3IG4-oyJEWWtb.js → wardleyDiagram-VM6X3IG4-Cms1K_3v.js} +1 -1
- package/dist/{xychartDiagram-S5SC5T6Z-DMjWgQPm.js → xychartDiagram-S5SC5T6Z-_kUiODzS.js} +1 -1
- package/package.json +1 -1
- package/src/__mocks__/requests.ts +0 -2
- package/src/components/chat/__tests__/notebook-context.test.ts +199 -0
- package/src/components/chat/chat-panel.tsx +33 -15
- package/src/components/chat/notebook-context.ts +80 -0
- package/src/components/editor/cell/StopButton.tsx +3 -3
- package/src/components/editor/cell/cell-context-menu.tsx +18 -2
- package/src/components/editor/cell/code/__tests__/language-toggle.test.tsx +38 -1
- package/src/components/editor/cell/code/cell-editor.tsx +2 -1
- package/src/components/editor/cell/code/language-toggle.tsx +6 -4
- package/src/components/editor/chrome/wrapper/__tests__/document-sync-status.test.tsx +9 -6
- package/src/components/slides/slide-cell-view.tsx +2 -1
- package/src/components/ui/__tests__/fullscreen.test.tsx +56 -1
- package/src/components/ui/fullscreen.tsx +18 -2
- package/src/components/ui/slider.tsx +6 -2
- package/src/core/codemirror/copilot/getCodes.ts +1 -1
- package/src/core/edit-app.tsx +5 -4
- package/src/core/executions/__tests__/input.test.ts +1 -1
- package/src/core/executions/__tests__/interrupt.test.ts +200 -0
- package/src/core/executions/__tests__/run.test.ts +3 -3
- package/src/core/executions/index.ts +1 -0
- package/src/core/executions/interrupt.ts +49 -0
- package/src/core/islands/bridge.ts +0 -2
- package/src/core/network/requests-network.ts +0 -15
- package/src/core/network/requests-static.ts +0 -2
- package/src/core/network/requests-toasting.tsx +0 -2
- package/src/core/network/types.ts +0 -3
- package/src/core/notebook/document/__tests__/model.test.ts +4 -4
- package/src/core/notebook/document/__tests__/test-host.test.ts +6 -6
- package/src/core/notebook/document/__tests__/test-host.ts +42 -46
- package/src/core/notebook/document/__tests__/test-notebook.ts +5 -4
- package/src/core/notebook/document/sync.ts +12 -5
- package/src/core/notebook/replica/__tests__/fixtures.ts +8 -0
- package/src/core/notebook/replica/backend.ts +1 -1
- package/src/core/saving/__tests__/document.test.tsx +1 -1
- package/src/core/transports/__tests__/static.test.ts +1 -1
- package/src/core/transports/__tests__/wasm.test.ts +1 -1
- package/src/core/transports/static.ts +8 -2
- package/src/core/transports/wasm.ts +2 -4
- package/src/core/wasm/__tests__/bridge.test.ts +170 -26
- package/src/core/wasm/bridge.ts +64 -19
- package/src/core/wasm/worker/types.ts +0 -1
- package/src/plugins/impl/DataEditorPlugin.tsx +32 -21
- package/src/plugins/impl/SliderPlugin.tsx +35 -3
- package/src/plugins/impl/__test__/slider-labels.test.tsx +30 -0
- package/src/plugins/impl/__tests__/DataEditorPlugin.test.ts +103 -12
- package/src/plugins/impl/__tests__/SliderPlugin.test.tsx +40 -0
- package/src/plugins/impl/data-editor/__tests__/glide-data-editor.test.tsx +159 -4
- package/src/plugins/impl/data-editor/glide-data-editor.tsx +30 -10
- package/src/plugins/impl/data-editor/glide-portal.tsx +5 -3
- package/src/plugins/layout/AccordionPlugin.tsx +2 -1
- package/src/plugins/layout/__tests__/AccordionPlugin.test.tsx +21 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as e } from "./rolldown-runtime-BPCzCO3I.js";
|
|
2
2
|
import { t } from "./react-Bgs_wQh3.js";
|
|
3
|
-
import { h as n } from "./tooltip-
|
|
4
|
-
import { C as r } from "./select-
|
|
3
|
+
import { h as n } from "./tooltip-BVbJPkcl.js";
|
|
4
|
+
import { C as r } from "./select-suaAxFuo.js";
|
|
5
5
|
var i = n("chart-pie", [["path", {
|
|
6
6
|
d: "M21 12c.552 0 1.005-.449.95-.998a10 10 0 0 0-8.953-8.951c-.55-.055-.998.398-.998.95v8a1 1 0 0 0 1 1z",
|
|
7
7
|
key: "pzmjnu"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as e } from "./rolldown-runtime-BPCzCO3I.js";
|
|
2
2
|
import { t } from "./react-Bgs_wQh3.js";
|
|
3
|
-
import {
|
|
3
|
+
import { Pt as n } from "./use-restore-focus-tPmARo1Q.js";
|
|
4
4
|
//#region src/hooks/useDeepCompareMemoize.ts
|
|
5
5
|
var r = /* @__PURE__ */ e(t(), 1);
|
|
6
6
|
function i(e) {
|
|
@@ -2,7 +2,7 @@ import { a as e } from "./rolldown-runtime-BPCzCO3I.js";
|
|
|
2
2
|
import { h as t, r as n } from "./button-qQhINE7z.js";
|
|
3
3
|
import { t as r } from "./react-Bgs_wQh3.js";
|
|
4
4
|
import { t as i } from "./compiler-runtime-C5KHtL5D.js";
|
|
5
|
-
import { h as a } from "./tooltip-
|
|
5
|
+
import { h as a } from "./tooltip-BVbJPkcl.js";
|
|
6
6
|
import { t as o } from "./jsx-runtime-D8btoEHk.js";
|
|
7
7
|
var s = a("calendar", [
|
|
8
8
|
["path", {
|
|
@@ -2,22 +2,22 @@ import { a as e } from "./rolldown-runtime-BPCzCO3I.js";
|
|
|
2
2
|
import { g as t, h as n, m as r, s as i } from "./button-qQhINE7z.js";
|
|
3
3
|
import { t as a } from "./react-Bgs_wQh3.js";
|
|
4
4
|
import { t as o } from "./compiler-runtime-C5KHtL5D.js";
|
|
5
|
-
import { t as s } from "./tooltip-
|
|
6
|
-
import { l as c, t as l } from "./config-
|
|
5
|
+
import { t as s } from "./tooltip-BVbJPkcl.js";
|
|
6
|
+
import { l as c, t as l } from "./config-CvBnR945.js";
|
|
7
7
|
import { t as u } from "./jsx-runtime-D8btoEHk.js";
|
|
8
|
-
import {
|
|
9
|
-
import { n as f } from "./error-banner-
|
|
8
|
+
import { d } from "./use-restore-focus-tPmARo1Q.js";
|
|
9
|
+
import { n as f } from "./error-banner-DUB_qUeL.js";
|
|
10
10
|
import { t as p } from "./debounce-DrhhziJv.js";
|
|
11
11
|
import { t as ee } from "./objects-DCmMvZtn.js";
|
|
12
12
|
import { t as te } from "./useEvent-BoN7U38T.js";
|
|
13
|
-
import { a as ne, i as re, n as ie, t as m } from "./formats-
|
|
13
|
+
import { a as ne, i as re, n as ie, t as m } from "./formats-hF6fETr6.js";
|
|
14
14
|
import { a as h, t as g } from "./arrays-DoQ-AILx.js";
|
|
15
15
|
import { t as ae } from "./useAsyncData-P5-Oovhq.js";
|
|
16
16
|
import { t as _ } from "./semaphore-8KhQouXt.js";
|
|
17
17
|
import { W as oe, n as se } from "./vega-loader.browser-Co9gYE8Z.js";
|
|
18
18
|
import { t as ce } from "./react-vega-CGgQEf0O.js";
|
|
19
19
|
import { a as le, n as v } from "./loader-Bin_dutt.js";
|
|
20
|
-
import { t as ue } from "./useDeepCompareMemoize-
|
|
20
|
+
import { t as ue } from "./useDeepCompareMemoize-Bcu0DkCS.js";
|
|
21
21
|
import { t as de } from "./use-vega-container-remeasure-BrUpWQfF.js";
|
|
22
22
|
//#region src/plugins/impl/vega/fix-relative-url.ts
|
|
23
23
|
var fe = /* @__PURE__ */ e(a(), 1), pe = o();
|
|
@@ -3,7 +3,7 @@ import { t } from "./src-D5uZaZib.js";
|
|
|
3
3
|
import { n } from "./chunk-Y2CYZVJY-DKKS1VyV.js";
|
|
4
4
|
import { $ as r, H as i, K as a, U as o, a as s, b as c, c as l, et as u, f as d, nt as f, tt as p, v as m, w as h, y as g } from "./chunk-DU6HZSFF-4SDIhUTY.js";
|
|
5
5
|
import { t as _ } from "./rough.esm-CtV9AnV1.js";
|
|
6
|
-
import { p as v } from "./mermaid
|
|
6
|
+
import { p as v } from "./mermaid--2K0cmt9.js";
|
|
7
7
|
//#region ../node_modules/.pnpm/khroma@2.1.0/node_modules/khroma/dist/methods/transparentize.js
|
|
8
8
|
var y = (e, t) => p(e, "a", -t), b = 1e-10;
|
|
9
9
|
function x(e, t) {
|
|
@@ -2,7 +2,7 @@ import { i as e } from "./chunk-75Z2AOVW-76L6My3P.js";
|
|
|
2
2
|
import { n as t } from "./src-D5uZaZib.js";
|
|
3
3
|
import { n } from "./chunk-Y2CYZVJY-DKKS1VyV.js";
|
|
4
4
|
import { D as r, H as i, K as a, U as o, a as s, b as c, c as l, v as u, w as d, x as f, y as p } from "./chunk-DU6HZSFF-4SDIhUTY.js";
|
|
5
|
-
import { p as m } from "./mermaid
|
|
5
|
+
import { p as m } from "./mermaid--2K0cmt9.js";
|
|
6
6
|
import { n as h } from "./mermaid-parser.core-DtOnl7m4.js";
|
|
7
7
|
import { t as g } from "./chunk-JWPE2WC7-DJvv1t8U.js";
|
|
8
8
|
//#region ../node_modules/.pnpm/mermaid@11.17.2/node_modules/mermaid/dist/chunks/mermaid.core/wardleyDiagram-VM6X3IG4.mjs
|
|
@@ -9,7 +9,7 @@ import { n as s } from "./chunk-Y2CYZVJY-DKKS1VyV.js";
|
|
|
9
9
|
import { D as c, H as l, K as u, U as d, a as f, b as p, c as m, f as h, v as g, w as _, y as v, z as y } from "./chunk-DU6HZSFF-4SDIhUTY.js";
|
|
10
10
|
import "./chunk-PWAF6VOD-CRu_RGP2.js";
|
|
11
11
|
import { t as b } from "./chunk-GMAD6QVW-BJGF8QZL.js";
|
|
12
|
-
import { p as x } from "./mermaid
|
|
12
|
+
import { p as x } from "./mermaid--2K0cmt9.js";
|
|
13
13
|
//#region ../node_modules/.pnpm/d3-scale@4.0.2/node_modules/d3-scale/src/band.js
|
|
14
14
|
function S() {
|
|
15
15
|
var e = t().unknown(void 0), r = e.domain, i = e.range, o = 0, s = 1, c, l, u = !1, d = 0, f = 0, p = .5;
|
package/package.json
CHANGED
|
@@ -19,9 +19,7 @@ export const MockRequestClient = {
|
|
|
19
19
|
sendRestart: vi.fn().mockResolvedValue({}),
|
|
20
20
|
saveLayout: vi.fn().mockResolvedValue({}),
|
|
21
21
|
sendCopy: vi.fn().mockResolvedValue({}),
|
|
22
|
-
sendStdin: vi.fn().mockResolvedValue({}),
|
|
23
22
|
sendFormat: vi.fn().mockResolvedValue({ codes: {} }),
|
|
24
|
-
sendInterrupt: vi.fn().mockResolvedValue({}),
|
|
25
23
|
sendShutdown: vi.fn().mockResolvedValue({}),
|
|
26
24
|
sendRunScratchpad: vi.fn().mockResolvedValue({}),
|
|
27
25
|
sendInstantiate: vi.fn().mockResolvedValue({}),
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { type UIMessage, validateUIMessages } from "ai";
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
import { withNotebookContext } from "../notebook-context";
|
|
6
|
+
|
|
7
|
+
const question: UIMessage["parts"] = [{ type: "text", text: "Help me" }];
|
|
8
|
+
|
|
9
|
+
function user(parts: UIMessage["parts"]): UIMessage {
|
|
10
|
+
return { id: "user", role: "user", parts };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function context(data: unknown) {
|
|
14
|
+
return { type: "data-marimo-notebook", data };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const initial = {
|
|
18
|
+
sessionId: "session-1",
|
|
19
|
+
cells: { a: "x = 1", b: "y = x + 1" },
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function initialHistory() {
|
|
23
|
+
return [user(withNotebookContext(question, [], initial))];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
describe("notebook context", () => {
|
|
27
|
+
it("captures a complete initial snapshot including empty cells", () => {
|
|
28
|
+
expect(
|
|
29
|
+
withNotebookContext(question, [], {
|
|
30
|
+
sessionId: "session-1",
|
|
31
|
+
cells: { a: "" },
|
|
32
|
+
}),
|
|
33
|
+
).toEqual([
|
|
34
|
+
context({
|
|
35
|
+
sessionId: "session-1",
|
|
36
|
+
cellIds: ["a"],
|
|
37
|
+
cells: [{ id: "a", code: "" }],
|
|
38
|
+
}),
|
|
39
|
+
...question,
|
|
40
|
+
]);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("sends only a snapshot marker after restoring unchanged history", async () => {
|
|
44
|
+
const savedHistory = JSON.stringify(initialHistory());
|
|
45
|
+
const restored = await validateUIMessages({
|
|
46
|
+
messages: JSON.parse(savedHistory),
|
|
47
|
+
});
|
|
48
|
+
expect(withNotebookContext(question, restored, initial)).toEqual([
|
|
49
|
+
context({ sessionId: "session-1", cells: [] }),
|
|
50
|
+
...question,
|
|
51
|
+
]);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("sends only changed or added cells without mutating the history", () => {
|
|
55
|
+
const history = initialHistory();
|
|
56
|
+
const saved = structuredClone(history);
|
|
57
|
+
expect(
|
|
58
|
+
withNotebookContext(question, history, {
|
|
59
|
+
sessionId: "session-1",
|
|
60
|
+
cells: { a: "x = 2", b: "y = x + 1", c: "" },
|
|
61
|
+
}),
|
|
62
|
+
).toEqual([
|
|
63
|
+
context({
|
|
64
|
+
sessionId: "session-1",
|
|
65
|
+
cellIds: ["a", "b", "c"],
|
|
66
|
+
cells: [
|
|
67
|
+
{ id: "a", code: "x = 2" },
|
|
68
|
+
{ id: "c", code: "" },
|
|
69
|
+
],
|
|
70
|
+
}),
|
|
71
|
+
...question,
|
|
72
|
+
]);
|
|
73
|
+
expect(history).toEqual(saved);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("tracks deletions, reordering, and re-added cells", () => {
|
|
77
|
+
const history = initialHistory();
|
|
78
|
+
const deleted = withNotebookContext(question, history, {
|
|
79
|
+
sessionId: "session-1",
|
|
80
|
+
cells: { b: "y = x + 1" },
|
|
81
|
+
});
|
|
82
|
+
expect(deleted).toEqual([
|
|
83
|
+
context({ sessionId: "session-1", cellIds: ["b"], cells: [] }),
|
|
84
|
+
...question,
|
|
85
|
+
]);
|
|
86
|
+
history.push(user(deleted));
|
|
87
|
+
const readded = withNotebookContext(question, history, initial);
|
|
88
|
+
expect(readded).toEqual([
|
|
89
|
+
context({
|
|
90
|
+
sessionId: "session-1",
|
|
91
|
+
cellIds: ["a", "b"],
|
|
92
|
+
cells: [{ id: "a", code: "x = 1" }],
|
|
93
|
+
}),
|
|
94
|
+
...question,
|
|
95
|
+
]);
|
|
96
|
+
history.push(user(readded));
|
|
97
|
+
expect(
|
|
98
|
+
withNotebookContext(question, history, {
|
|
99
|
+
sessionId: "session-1",
|
|
100
|
+
cells: { b: "y = x + 1", a: "x = 1" },
|
|
101
|
+
}),
|
|
102
|
+
).toEqual([
|
|
103
|
+
context({ sessionId: "session-1", cellIds: ["b", "a"], cells: [] }),
|
|
104
|
+
...question,
|
|
105
|
+
]);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("represents an empty notebook explicitly", () => {
|
|
109
|
+
expect(
|
|
110
|
+
withNotebookContext(question, initialHistory(), {
|
|
111
|
+
sessionId: "session-1",
|
|
112
|
+
cells: {},
|
|
113
|
+
}),
|
|
114
|
+
).toEqual([
|
|
115
|
+
context({ sessionId: "session-1", cellIds: [], cells: [] }),
|
|
116
|
+
...question,
|
|
117
|
+
]);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("uses only the retained history when editing a message", () => {
|
|
121
|
+
const history = initialHistory();
|
|
122
|
+
const changed = { sessionId: "session-1", cells: { a: "x = 2" } };
|
|
123
|
+
const next = withNotebookContext(question, history, changed);
|
|
124
|
+
expect(
|
|
125
|
+
withNotebookContext(question, [...history, user(next)], initial),
|
|
126
|
+
).toEqual([
|
|
127
|
+
context({
|
|
128
|
+
sessionId: "session-1",
|
|
129
|
+
cellIds: ["a", "b"],
|
|
130
|
+
cells: [
|
|
131
|
+
{ id: "a", code: "x = 1" },
|
|
132
|
+
{ id: "b", code: "y = x + 1" },
|
|
133
|
+
],
|
|
134
|
+
}),
|
|
135
|
+
...question,
|
|
136
|
+
]);
|
|
137
|
+
expect(withNotebookContext(question, history, initial)).toEqual([
|
|
138
|
+
context({ sessionId: "session-1", cells: [] }),
|
|
139
|
+
...question,
|
|
140
|
+
]);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("updates session identity without repeating code", () => {
|
|
144
|
+
expect(
|
|
145
|
+
withNotebookContext(question, initialHistory(), {
|
|
146
|
+
...initial,
|
|
147
|
+
sessionId: "session-2",
|
|
148
|
+
}),
|
|
149
|
+
).toEqual([context({ sessionId: "session-2", cells: [] }), ...question]);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("captures a full snapshot for chats created before notebook context existed", () => {
|
|
153
|
+
const legacyHistory = [user(question)];
|
|
154
|
+
expect(withNotebookContext(question, legacyHistory, initial)).toEqual(
|
|
155
|
+
initialHistory()[0].parts,
|
|
156
|
+
);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("compares against user snapshots independently of tool results", () => {
|
|
160
|
+
const history = initialHistory();
|
|
161
|
+
history.push({
|
|
162
|
+
id: "tool-result",
|
|
163
|
+
role: "assistant",
|
|
164
|
+
parts: [
|
|
165
|
+
{
|
|
166
|
+
type: "tool-edit_cell",
|
|
167
|
+
toolCallId: "edit-a",
|
|
168
|
+
state: "output-available",
|
|
169
|
+
input: { id: "a", code: "x = 2" },
|
|
170
|
+
output: { code: "x = 2" },
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
});
|
|
174
|
+
expect(
|
|
175
|
+
withNotebookContext(question, history, {
|
|
176
|
+
sessionId: "session-1",
|
|
177
|
+
cells: { a: "x = 2", b: "y = x + 1" },
|
|
178
|
+
}),
|
|
179
|
+
).toEqual([
|
|
180
|
+
context({
|
|
181
|
+
sessionId: "session-1",
|
|
182
|
+
cells: [{ id: "a", code: "x = 2" }],
|
|
183
|
+
}),
|
|
184
|
+
...question,
|
|
185
|
+
]);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("can enter and leave full access without sending its notebook code", () => {
|
|
189
|
+
const full = withNotebookContext(question, [], { sessionId: "session-1" });
|
|
190
|
+
expect(full).toEqual([context({ sessionId: "session-1" }), ...question]);
|
|
191
|
+
const read = withNotebookContext(question, [user(full)], initial);
|
|
192
|
+
expect(read).toEqual(initialHistory()[0].parts);
|
|
193
|
+
expect(
|
|
194
|
+
withNotebookContext(question, [user(full), user(read)], {
|
|
195
|
+
sessionId: "session-1",
|
|
196
|
+
}),
|
|
197
|
+
).toEqual([context({ sessionId: "session-1" }), ...question]);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
@@ -93,7 +93,9 @@ import {
|
|
|
93
93
|
useFileState,
|
|
94
94
|
useMessageQueue,
|
|
95
95
|
} from "./chat-utils";
|
|
96
|
-
import {
|
|
96
|
+
import { notebookCellCodes } from "@/core/codemirror/copilot/getCodes";
|
|
97
|
+
import { getSessionId } from "@/core/kernel/session";
|
|
98
|
+
import { withNotebookContext } from "./notebook-context";
|
|
97
99
|
import { focusInputAndMoveToEnd } from "@/core/codemirror/utils";
|
|
98
100
|
import ScrollToBottomButton from "./acp/scroll-to-bottom-button";
|
|
99
101
|
import { useChatControllerId } from "./use-chat-controller-id";
|
|
@@ -501,7 +503,6 @@ const ChatPanelBody = () => {
|
|
|
501
503
|
|
|
502
504
|
const completionBody = {
|
|
503
505
|
uiMessages: options.messages,
|
|
504
|
-
includeOtherCode: getCodes(""),
|
|
505
506
|
options: store.get(chatOptionsAtom),
|
|
506
507
|
};
|
|
507
508
|
|
|
@@ -588,10 +589,21 @@ const ChatPanelBody = () => {
|
|
|
588
589
|
},
|
|
589
590
|
});
|
|
590
591
|
|
|
592
|
+
const contextualize = useEvent(
|
|
593
|
+
(parts: ChatMessagePart[], history: UIMessage[]) =>
|
|
594
|
+
withNotebookContext(parts, history, {
|
|
595
|
+
sessionId: getSessionId(),
|
|
596
|
+
cells:
|
|
597
|
+
store.get(aiAtom)?.mode === "code_mode"
|
|
598
|
+
? undefined
|
|
599
|
+
: store.get(notebookCellCodes),
|
|
600
|
+
}),
|
|
601
|
+
);
|
|
602
|
+
|
|
591
603
|
const sendUserMessage = useEvent((parts: ChatMessagePart[]) => {
|
|
592
604
|
clearAbortState();
|
|
593
605
|
turn.start();
|
|
594
|
-
sendMessage({ role: "user", parts });
|
|
606
|
+
sendMessage({ role: "user", parts: contextualize(parts, messages) });
|
|
595
607
|
});
|
|
596
608
|
|
|
597
609
|
const tryFlushQueuedMessages = useEvent(
|
|
@@ -753,12 +765,15 @@ const ChatPanelBody = () => {
|
|
|
753
765
|
turn.start();
|
|
754
766
|
sendMessage({
|
|
755
767
|
role: "user",
|
|
756
|
-
parts:
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
768
|
+
parts: contextualize(
|
|
769
|
+
[
|
|
770
|
+
{ type: "text" as const, text: initialMessage },
|
|
771
|
+
...(contextPart ? [contextPart] : []),
|
|
772
|
+
...(fileParts ?? []),
|
|
773
|
+
...attachments,
|
|
774
|
+
],
|
|
775
|
+
[],
|
|
776
|
+
),
|
|
762
777
|
});
|
|
763
778
|
clearFiles();
|
|
764
779
|
setInput("");
|
|
@@ -812,12 +827,15 @@ const ChatPanelBody = () => {
|
|
|
812
827
|
sendMessage({
|
|
813
828
|
messageId: messageId, // replace the message
|
|
814
829
|
role: "user",
|
|
815
|
-
parts:
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
830
|
+
parts: contextualize(
|
|
831
|
+
[
|
|
832
|
+
{ type: "text", text: newValue },
|
|
833
|
+
...(contextPart ? [contextPart] : []),
|
|
834
|
+
...userFileParts,
|
|
835
|
+
...attachments,
|
|
836
|
+
],
|
|
837
|
+
messages.slice(0, index),
|
|
838
|
+
),
|
|
821
839
|
});
|
|
822
840
|
},
|
|
823
841
|
);
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import type { DataUIPart, UIMessage } from "ai";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
|
|
6
|
+
const notebookContextSchema = z.object({
|
|
7
|
+
sessionId: z.string(),
|
|
8
|
+
cells: z.array(z.object({ id: z.string(), code: z.string() })).optional(),
|
|
9
|
+
cellIds: z.array(z.string()).optional(),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
type NotebookContext = z.infer<typeof notebookContextSchema>;
|
|
13
|
+
type NotebookContextPart = DataUIPart<{
|
|
14
|
+
"marimo-notebook": NotebookContext;
|
|
15
|
+
}>;
|
|
16
|
+
|
|
17
|
+
export const NOTEBOOK_CONTEXT_PART_TYPE =
|
|
18
|
+
"data-marimo-notebook" as const satisfies NotebookContextPart["type"];
|
|
19
|
+
|
|
20
|
+
interface NotebookSnapshot {
|
|
21
|
+
sessionId: string;
|
|
22
|
+
cells?: Readonly<Record<string, string>>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function withNotebookContext(
|
|
26
|
+
parts: UIMessage["parts"],
|
|
27
|
+
history: UIMessage[],
|
|
28
|
+
snapshot: NotebookSnapshot,
|
|
29
|
+
): UIMessage["parts"] {
|
|
30
|
+
let cellIds: string[] | undefined;
|
|
31
|
+
const cells = new Map<string, string>();
|
|
32
|
+
for (const message of history) {
|
|
33
|
+
if (message.role !== "user") {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
for (const part of message.parts) {
|
|
37
|
+
if (part.type !== NOTEBOOK_CONTEXT_PART_TYPE) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const parsed = notebookContextSchema.safeParse(part.data);
|
|
41
|
+
if (!parsed.success) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (parsed.data.cellIds) {
|
|
45
|
+
cellIds = parsed.data.cellIds;
|
|
46
|
+
const retained = new Set(cellIds);
|
|
47
|
+
for (const id of cells.keys()) {
|
|
48
|
+
if (!retained.has(id)) {
|
|
49
|
+
cells.delete(id);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
for (const cell of parsed.data.cells ?? []) {
|
|
54
|
+
cells.set(cell.id, cell.code);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const update: NotebookContext = { sessionId: snapshot.sessionId };
|
|
60
|
+
if (snapshot.cells) {
|
|
61
|
+
const nextIds = Object.keys(snapshot.cells);
|
|
62
|
+
if (
|
|
63
|
+
!cellIds ||
|
|
64
|
+
nextIds.length !== cellIds.length ||
|
|
65
|
+
nextIds.some((id, index) => id !== cellIds[index])
|
|
66
|
+
) {
|
|
67
|
+
update.cellIds = nextIds;
|
|
68
|
+
}
|
|
69
|
+
const changed = Object.entries(snapshot.cells)
|
|
70
|
+
.filter(([id, code]) => cells.get(id) !== code)
|
|
71
|
+
.map(([id, code]) => ({ id, code }));
|
|
72
|
+
update.cells = changed;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const context: NotebookContextPart = {
|
|
76
|
+
type: NOTEBOOK_CONTEXT_PART_TYPE,
|
|
77
|
+
data: update,
|
|
78
|
+
};
|
|
79
|
+
return [context, ...parts];
|
|
80
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
import { SquareIcon } from "lucide-react";
|
|
3
3
|
import type { JSX } from "react";
|
|
4
|
-
import {
|
|
4
|
+
import { interruptRuntime } from "@/core/executions";
|
|
5
|
+
import { store } from "@/core/state/jotai";
|
|
5
6
|
import type { RuntimeState } from "@/core/network/types";
|
|
6
7
|
import { isAppInteractionDisabled } from "@/core/session/connection-utils";
|
|
7
8
|
import type { ConnectionState } from "@/core/session/types";
|
|
@@ -15,7 +16,6 @@ export const StopButton = (props: {
|
|
|
15
16
|
connectionState: ConnectionState;
|
|
16
17
|
}): JSX.Element => {
|
|
17
18
|
const { connectionState, status } = props;
|
|
18
|
-
const { sendInterrupt } = useRequestClient();
|
|
19
19
|
|
|
20
20
|
const running = status === "running";
|
|
21
21
|
|
|
@@ -26,7 +26,7 @@ export const StopButton = (props: {
|
|
|
26
26
|
<ToolbarItem
|
|
27
27
|
tooltip={renderShortcut("global.interrupt")}
|
|
28
28
|
disabled={isAppInteractionDisabled(connectionState) || !showInterrupt}
|
|
29
|
-
onClick={showInterrupt ?
|
|
29
|
+
onClick={showInterrupt ? () => interruptRuntime(store) : Functions.NOOP}
|
|
30
30
|
variant={showInterrupt ? "stale" : "disabled"}
|
|
31
31
|
data-testid="run-button"
|
|
32
32
|
>
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
import { menuItemVariants } from "@/components/ui/menu-items";
|
|
21
21
|
import { Tooltip } from "@/components/ui/tooltip";
|
|
22
22
|
import { toast } from "@/components/ui/use-toast";
|
|
23
|
+
import { useRestoreFocus } from "@/components/ui/use-restore-focus";
|
|
23
24
|
import { useCellData, useCellRuntime } from "@/core/cells/cells";
|
|
24
25
|
import { CellOutputId } from "@/core/cells/ids";
|
|
25
26
|
import { isOutputEmpty } from "@/core/cells/outputs";
|
|
@@ -71,6 +72,8 @@ export const CellActionsContextMenu = ({
|
|
|
71
72
|
const [imageRightClicked, setImageRightClicked] =
|
|
72
73
|
React.useState<HTMLImageElement>();
|
|
73
74
|
const suppressCloseAutoFocus = React.useRef(false);
|
|
75
|
+
const pendingAction = React.useRef<(() => void) | null>(null);
|
|
76
|
+
const restoreFocus = useRestoreFocus();
|
|
74
77
|
|
|
75
78
|
const DEFAULT_CONTEXT_MENU_ITEMS: ActionButton[] = [
|
|
76
79
|
{
|
|
@@ -194,7 +197,13 @@ export const CellActionsContextMenu = ({
|
|
|
194
197
|
.filter((group) => group.length > 0);
|
|
195
198
|
|
|
196
199
|
return (
|
|
197
|
-
<ContextMenu
|
|
200
|
+
<ContextMenu
|
|
201
|
+
onOpenChange={(open) => {
|
|
202
|
+
if (open) {
|
|
203
|
+
restoreFocus.onOpenAutoFocus();
|
|
204
|
+
}
|
|
205
|
+
}}
|
|
206
|
+
>
|
|
198
207
|
<ContextMenuTrigger
|
|
199
208
|
disabled={disabled}
|
|
200
209
|
onContextMenu={(evt) => {
|
|
@@ -212,6 +221,13 @@ export const CellActionsContextMenu = ({
|
|
|
212
221
|
className="w-[300px]"
|
|
213
222
|
scrollable={true}
|
|
214
223
|
onCloseAutoFocus={(evt) => {
|
|
224
|
+
const action = pendingAction.current;
|
|
225
|
+
pendingAction.current = null;
|
|
226
|
+
if (action) {
|
|
227
|
+
restoreFocus.onCloseAutoFocus(evt);
|
|
228
|
+
evt.preventDefault();
|
|
229
|
+
action();
|
|
230
|
+
}
|
|
215
231
|
if (suppressCloseAutoFocus.current) {
|
|
216
232
|
evt.preventDefault();
|
|
217
233
|
suppressCloseAutoFocus.current = false;
|
|
@@ -270,7 +286,7 @@ export const CellActionsContextMenu = ({
|
|
|
270
286
|
if (action.disableClick || action.disabled) {
|
|
271
287
|
return;
|
|
272
288
|
}
|
|
273
|
-
action.handle(evt);
|
|
289
|
+
pendingAction.current = () => action.handle(evt);
|
|
274
290
|
}}
|
|
275
291
|
variant={action.variant}
|
|
276
292
|
>
|
|
@@ -7,7 +7,7 @@ import { createRef } from "react";
|
|
|
7
7
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
8
8
|
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
9
9
|
import { switchLanguage } from "@/core/codemirror/language/extension";
|
|
10
|
-
import { LanguageToggle } from "../language-toggle";
|
|
10
|
+
import { LanguageToggle, LanguageToggles } from "../language-toggle";
|
|
11
11
|
|
|
12
12
|
vi.mock("@/core/codemirror/language/extension", () => ({
|
|
13
13
|
switchLanguage: vi.fn(),
|
|
@@ -51,4 +51,41 @@ describe("LanguageToggle", () => {
|
|
|
51
51
|
view.destroy();
|
|
52
52
|
}
|
|
53
53
|
});
|
|
54
|
+
|
|
55
|
+
it("uses the correct callback for each language toggle", () => {
|
|
56
|
+
const view = new EditorView({ state: EditorState.create() });
|
|
57
|
+
const editorViewRef = createRef<EditorView>();
|
|
58
|
+
editorViewRef.current = view;
|
|
59
|
+
|
|
60
|
+
const onAfterToggleSQL = vi.fn();
|
|
61
|
+
const onAfterToggleMarkdown = vi.fn();
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
render(
|
|
65
|
+
<TooltipProvider>
|
|
66
|
+
<LanguageToggles
|
|
67
|
+
editorViewRef={editorViewRef}
|
|
68
|
+
code=""
|
|
69
|
+
currentLanguageAdapter="python"
|
|
70
|
+
onAfterToggleSQL={onAfterToggleSQL}
|
|
71
|
+
onAfterToggleMarkdown={onAfterToggleMarkdown}
|
|
72
|
+
/>
|
|
73
|
+
</TooltipProvider>,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const toggleButtons = screen.getAllByTestId("language-toggle-button");
|
|
77
|
+
|
|
78
|
+
fireEvent.click(toggleButtons[0]);
|
|
79
|
+
|
|
80
|
+
expect(onAfterToggleSQL).toHaveBeenCalledOnce();
|
|
81
|
+
expect(onAfterToggleMarkdown).not.toHaveBeenCalled();
|
|
82
|
+
|
|
83
|
+
fireEvent.click(toggleButtons[1]);
|
|
84
|
+
|
|
85
|
+
expect(onAfterToggleMarkdown).toHaveBeenCalledOnce();
|
|
86
|
+
expect(onAfterToggleSQL).toHaveBeenCalledOnce();
|
|
87
|
+
} finally {
|
|
88
|
+
view.destroy();
|
|
89
|
+
}
|
|
90
|
+
});
|
|
54
91
|
});
|
|
@@ -511,7 +511,8 @@ const CellEditorInternal = ({
|
|
|
511
511
|
code={code}
|
|
512
512
|
editorViewRef={editorViewRef}
|
|
513
513
|
currentLanguageAdapter={languageAdapter}
|
|
514
|
-
|
|
514
|
+
onAfterToggleSQL={afterToggleSQL}
|
|
515
|
+
onAfterToggleMarkdown={afterToggleMarkdown}
|
|
515
516
|
/>
|
|
516
517
|
</div>
|
|
517
518
|
)}
|
|
@@ -16,7 +16,8 @@ interface LanguageTogglesProps {
|
|
|
16
16
|
editorViewRef: React.RefObject<EditorView | null>;
|
|
17
17
|
code: string;
|
|
18
18
|
currentLanguageAdapter: LanguageAdapter["type"] | undefined;
|
|
19
|
-
|
|
19
|
+
onAfterToggleSQL: () => void;
|
|
20
|
+
onAfterToggleMarkdown: () => void;
|
|
20
21
|
/**
|
|
21
22
|
* Classes for the wrapper element. Defaults to the absolutely-positioned,
|
|
22
23
|
* hover-revealed placement used inside the notebook cell editor.
|
|
@@ -28,7 +29,8 @@ export const LanguageToggles: React.FC<LanguageTogglesProps> = ({
|
|
|
28
29
|
editorViewRef,
|
|
29
30
|
code,
|
|
30
31
|
currentLanguageAdapter,
|
|
31
|
-
|
|
32
|
+
onAfterToggleSQL,
|
|
33
|
+
onAfterToggleMarkdown,
|
|
32
34
|
className = "absolute right-3 top-2 z-20 flex hover-action gap-1",
|
|
33
35
|
}) => {
|
|
34
36
|
const canUseMarkdown = useMemo(
|
|
@@ -55,7 +57,7 @@ export const LanguageToggles: React.FC<LanguageTogglesProps> = ({
|
|
|
55
57
|
}
|
|
56
58
|
toType="sql"
|
|
57
59
|
displayName="SQL"
|
|
58
|
-
onAfterToggle={
|
|
60
|
+
onAfterToggle={onAfterToggleSQL}
|
|
59
61
|
/>
|
|
60
62
|
<LanguageToggle
|
|
61
63
|
editorViewRef={editorViewRef}
|
|
@@ -72,7 +74,7 @@ export const LanguageToggles: React.FC<LanguageTogglesProps> = ({
|
|
|
72
74
|
}
|
|
73
75
|
toType="markdown"
|
|
74
76
|
displayName="Markdown"
|
|
75
|
-
onAfterToggle={
|
|
77
|
+
onAfterToggle={onAfterToggleMarkdown}
|
|
76
78
|
/>
|
|
77
79
|
<LanguageToggle
|
|
78
80
|
editorViewRef={editorViewRef}
|