@marimo-team/islands 0.22.4-dev2 → 0.22.4-dev6

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.
@@ -5,7 +5,7 @@ import { s as __toESM, t as __commonJSMin } from "./chunk-BNovOVIE.js";
5
5
  import { t as require_react } from "./react-Bs6Z0kvn.js";
6
6
  import { t as require_compiler_runtime } from "./compiler-runtime-B_OLMU9S.js";
7
7
  import { r as toast } from "./copy-B7781WJ3.js";
8
- import { A as MarimoIncomingMessageEvent, At as moveToEndOfEditor, Bn as CircleX, C as contextToXml, D as AccordionContent, Dn as Wrench, Dt as createVariableInfoElement, E as Accordion, Fn as File$1, Gt as dataSourceConnectionsAtom, I as ChatBubbleIcon, Jt as getRequestClient, Kt as getTableType, Lt as jotaiJsonStorage, Mn as LoaderCircle, O as AccordionItem, On as Trash2, Pn as Info, Q as cellErrorsAtom, Qt as singleFacet, Rt as variablesAtom, S as Sections, T as AIContextRegistry, U as deserializeBlob, W as base64ToDataURL, Wt as allTablesAtom, Z as renderHTML, a as toPng, bt as displayCellName, cn as CellOutputId, d as Spinner, f as Popover, g as isOutputEmpty, h as PopoverTrigger, k as AccordionTrigger, m as PopoverContent, n as blobToString, nt as notebookAtom, o as MarkdownRenderer, rn as ZodLocalStorage, t as processOutput, w as AIContextProvider, x as Boosts, xn as Anchor2, y as DatasourceContextProvider, yn as atomWithStorage, zt as PluralWord } from "./process-output-DC1TOnIl.js";
8
+ import { A as MarimoIncomingMessageEvent, At as moveToEndOfEditor, Bn as CircleX, C as contextToXml, D as AccordionContent, Dn as Wrench, Dt as createVariableInfoElement, E as Accordion, Fn as File$1, Gt as dataSourceConnectionsAtom, I as ChatBubbleIcon, Jt as getRequestClient, Kt as getTableType, Lt as jotaiJsonStorage, Mn as LoaderCircle, O as AccordionItem, On as Trash2, Pn as Info, Q as cellErrorsAtom, Qt as singleFacet, Rt as variablesAtom, S as Sections, T as AIContextRegistry, U as deserializeBlob, W as base64ToDataURL, Wt as allTablesAtom, Z as renderHTML, a as toPng, bt as displayCellName, cn as CellOutputId, d as Spinner, f as Popover, g as isOutputEmpty, h as PopoverTrigger, k as AccordionTrigger, m as PopoverContent, n as blobToString, nt as notebookAtom, o as MarkdownRenderer, rn as ZodLocalStorage, t as processOutput, w as AIContextProvider, x as Boosts, xn as Anchor2, y as DatasourceContextProvider, yn as atomWithStorage, zt as PluralWord } from "./process-output-D1b_hWPJ.js";
9
9
  import "./chunk-5FQGJX7Z-C428iZBW.js";
10
10
  import { l as createLucideIcon } from "./dist-D_UjpfOY.js";
11
11
  import { C as logNever, I as X, n as Strings, t as Label } from "./label-DbZGAoCH.js";
package/dist/main.js CHANGED
@@ -21,7 +21,7 @@ import { a as __toCommonJS, n as __esmMin, r as __export, s as __toESM, t as __c
21
21
  import { t as require_react } from "./react-Bs6Z0kvn.js";
22
22
  import { t as require_compiler_runtime } from "./compiler-runtime-B_OLMU9S.js";
23
23
  import { n as Copy, r as toast, t as copyToClipboard } from "./copy-B7781WJ3.js";
24
- import { $ as createActions, $t as elementContainsMarimoCellFile, A as MarimoIncomingMessageEvent, An as PaintRoller, B as DotFilledIcon, Bn as CircleX, Bt as PluralWords, Cn as Content2$1, Ct as normalizeName, D as AccordionContent, Dn as Wrench, E as Accordion, En as Trigger2, Et as MarkdownLanguageAdapter, F as BorderAllIcon, Fn as File, Ft as repl, G as base64ToDataView, H as PinRightIcon, Hn as Braces, Ht as getDataTypeColor, In as FileText, It as adaptForLocalStorage, J as extractBase64FromDataURL, Jt as getRequestClient, K as base64ToUint8Array, L as CheckIcon, Ln as Eye, Lt as jotaiJsonStorage, M as MarimoValueReadyEvent, Mn as LoaderCircle, Mt as DeferredRequestRegistry, N as MarimoValueUpdateEvent, Nn as Layers, Nt as generateUUID, O as AccordionItem, On as Trash2, Ot as PathBuilder, P as createInputEvent, Pn as Info, Pt as useChromeActions, R as ChevronDownIcon, Rn as Database, Sn as Close$1, St as isInternalCellName, Tn as Root2$4, Tt as customPythonLanguageSupport, U as deserializeBlob, Un as esm_default$1, Ut as require_client, V as PinLeftIcon, Vn as CircleAlert, Vt as DATA_TYPE_ICON, Wn as import_lib, X as safeExtractSetUIElementMessageBuffers, Xt as useRequestClient, Y as isDataURLString, Yt as requestClientAtom, Z as renderHTML, Zt as isUninstantiated, _ as useExpandedConsoleOutput, _n as jsonToTSV, _t as headingToIdentifier, a as toPng, an as parseAttrValue, at as useCellActions, b as getDatasourceContext, bn as selectAtom, bt as displayCellName, c as useCellFocusActions, cn as CellOutputId, ct as createCell, d as Spinner, dn as UIElementId, dt as initialModeAtom, en as extractAllTracebackInfo, et as getCellEditorView, f as Popover$1, fn as findCellId, ft as kioskModeAtom, g as isOutputEmpty, gn as jsonToMarkdown, gt as isErrorMime, h as PopoverTrigger, hn as jsonParseWithSpecialChar, ht as outputIsStale, i as PythonIcon, in as filenameAtom, it as reducer, j as MarimoValueInputEvent, jn as NotebookPen, jt as goToCellLine, k as AccordionTrigger, kn as Table2, kt as Paths, l as useLastFocusedCellId, ln as HTMLCellId, lt as AnsiUp, m as PopoverContent, mn as RANDOM_ID_ATTR, mt as outputIsLoading, n as blobToString, nn as NotebookScopedLocalStorage, nt as notebookAtom, o as MarkdownRenderer, on as parseDataset, ot as useCellIds, p as PopoverClose$1, pn as OBJECT_ID_ATTR, pt as viewStateAtom, q as dataViewToBase64, qt as convertStatsName, r as filesToBase64, rt as notebookOutline, s as LazyAnyLanguageCodeMirror, sn as parseInitialValue, st as useCellNames, t as processOutput, tn as getTracebackInfo, tt as getCellNames, u as maybeAddAltairImport, un as SCRATCH_CELL_ID, ut as getInitialAppMode, v as useExpandedOutput, vn as atomWithReducer, vt as DATA_CELL_ID, wn as Item$1, wt as Checkbox, xt as getValidName, yn as atomWithStorage, yt as getCellDomProps, z as ChevronRightIcon, zn as Columns2, zt as PluralWord, __tla as __tla_0 } from "./process-output-DC1TOnIl.js";
24
+ import { $ as createActions, $t as elementContainsMarimoCellFile, A as MarimoIncomingMessageEvent, An as PaintRoller, B as DotFilledIcon, Bn as CircleX, Bt as PluralWords, Cn as Content2$1, Ct as normalizeName, D as AccordionContent, Dn as Wrench, E as Accordion, En as Trigger2, Et as MarkdownLanguageAdapter, F as BorderAllIcon, Fn as File, Ft as repl, G as base64ToDataView, H as PinRightIcon, Hn as Braces, Ht as getDataTypeColor, In as FileText, It as adaptForLocalStorage, J as extractBase64FromDataURL, Jt as getRequestClient, K as base64ToUint8Array, L as CheckIcon, Ln as Eye, Lt as jotaiJsonStorage, M as MarimoValueReadyEvent, Mn as LoaderCircle, Mt as DeferredRequestRegistry, N as MarimoValueUpdateEvent, Nn as Layers, Nt as generateUUID, O as AccordionItem, On as Trash2, Ot as PathBuilder, P as createInputEvent, Pn as Info, Pt as useChromeActions, R as ChevronDownIcon, Rn as Database, Sn as Close$1, St as isInternalCellName, Tn as Root2$4, Tt as customPythonLanguageSupport, U as deserializeBlob, Un as esm_default$1, Ut as require_client, V as PinLeftIcon, Vn as CircleAlert, Vt as DATA_TYPE_ICON, Wn as import_lib, X as safeExtractSetUIElementMessageBuffers, Xt as useRequestClient, Y as isDataURLString, Yt as requestClientAtom, Z as renderHTML, Zt as isUninstantiated, _ as useExpandedConsoleOutput, _n as jsonToTSV, _t as headingToIdentifier, a as toPng, an as parseAttrValue, at as useCellActions, b as getDatasourceContext, bn as selectAtom, bt as displayCellName, c as useCellFocusActions, cn as CellOutputId, ct as createCell, d as Spinner, dn as UIElementId, dt as initialModeAtom, en as extractAllTracebackInfo, et as getCellEditorView, f as Popover$1, fn as findCellId, ft as kioskModeAtom, g as isOutputEmpty, gn as jsonToMarkdown, gt as isErrorMime, h as PopoverTrigger, hn as jsonParseWithSpecialChar, ht as outputIsStale, i as PythonIcon, in as filenameAtom, it as reducer, j as MarimoValueInputEvent, jn as NotebookPen, jt as goToCellLine, k as AccordionTrigger, kn as Table2, kt as Paths, l as useLastFocusedCellId, ln as HTMLCellId, lt as AnsiUp, m as PopoverContent, mn as RANDOM_ID_ATTR, mt as outputIsLoading, n as blobToString, nn as NotebookScopedLocalStorage, nt as notebookAtom, o as MarkdownRenderer, on as parseDataset, ot as useCellIds, p as PopoverClose$1, pn as OBJECT_ID_ATTR, pt as viewStateAtom, q as dataViewToBase64, qt as convertStatsName, r as filesToBase64, rt as notebookOutline, s as LazyAnyLanguageCodeMirror, sn as parseInitialValue, st as useCellNames, t as processOutput, tn as getTracebackInfo, tt as getCellNames, u as maybeAddAltairImport, un as SCRATCH_CELL_ID, ut as getInitialAppMode, v as useExpandedOutput, vn as atomWithReducer, vt as DATA_CELL_ID, wn as Item$1, wt as Checkbox, xt as getValidName, yn as atomWithStorage, yt as getCellDomProps, z as ChevronRightIcon, zn as Columns2, zt as PluralWord, __tla as __tla_0 } from "./process-output-D1b_hWPJ.js";
25
25
  import { __tla as __tla_1 } from "./chunk-5FQGJX7Z-C428iZBW.js";
26
26
  import { l as createLucideIcon, o as useSize, s as Root$4 } from "./dist-D_UjpfOY.js";
27
27
  import { A as $896ba0a80a8f4d36$export$85fd5fdf27bacc79, C as DEFAULT_COLOR_SCHEME, D as SCALE_TYPE_DESCRIPTIONS, E as EMPTY_VALUE$1, F as ListFilter, I as ChartPie, L as ChartColumn, M as $5a387cc49350e6db$export$722debc0e56fea39, N as Table$1, O as TIME_UNIT_DESCRIPTIONS, P as SquareFunction, S as DEFAULT_AGGREGATION, T as DEFAULT_TIME_UNIT, _ as AGGREGATION_TYPE_DESCRIPTIONS, a as AGGREGATION_FNS$1, b as COLOR_SCHEMES, c as COLOR_BY_FIELDS, d as NONE_VALUE, f as SELECTABLE_DATA_TYPES, g as TIME_UNITS, h as STRING_AGGREGATION_FNS, i as convertDataTypeToSelectable, j as $fb18d541ea1ad717$export$ad991b66133851cf, k as escapeFieldName, l as COMBINED_TIME_UNITS, m as SORT_TYPES, n as createSpecWithoutData, o as BIN_AGGREGATION, p as SINGLE_TIME_UNITS, r as isFieldSet, s as CHART_TYPES, t as augmentSpecWithData, u as ChartType, v as AGGREGATION_TYPE_ICON, w as DEFAULT_MAX_BINS_FACET, x as COUNT_FIELD, y as CHART_TYPE_ICON } from "./spec-CD7QaCV-.js";
@@ -36594,12 +36594,13 @@ ${E}`,
36594
36594
  }
36595
36595
  const AnyWidgetPlugin = createPlugin("marimo-anywidget").withData(object({
36596
36596
  jsUrl: string(),
36597
- jsHash: string()
36597
+ jsHash: string(),
36598
+ modelId: string().transform((e) => e)
36598
36599
  })).withFunctions({}).renderer((e) => (0, import_jsx_runtime.jsx)(AnyWidgetSlot, {
36599
36600
  ...e
36600
36601
  }));
36601
36602
  var AnyWidgetSlot = (e) => {
36602
- let r = (0, import_compiler_runtime$91.c)(14), { jsUrl: c, jsHash: d } = e.data, { model_id: f } = e.value, h = e.host, _;
36603
+ let r = (0, import_compiler_runtime$91.c)(14), { jsUrl: c, jsHash: d, modelId: f } = e.data, h = e.host, _;
36603
36604
  r[0] !== d || r[1] !== c ? (_ = {
36604
36605
  jsUrl: c,
36605
36606
  jsHash: d
@@ -37075,7 +37076,7 @@ ${E}`,
37075
37076
  };
37076
37077
  }
37077
37078
  };
37078
- var LazyChatbot = import_react.lazy(() => import("./chat-ui-Cel1kBfc.js").then((e) => ({
37079
+ var LazyChatbot = import_react.lazy(() => import("./chat-ui-BlEsENC-.js").then((e) => ({
37079
37080
  default: e.Chatbot
37080
37081
  }))), messageSchema = array(object({
37081
37082
  id: string(),
@@ -65540,7 +65541,7 @@ ${c}
65540
65541
  return Logger.warn("Failed to get version from mount config"), null;
65541
65542
  }
65542
65543
  }
65543
- const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.22.4-dev2"), showCodeInRunModeAtom = atom(true);
65544
+ const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.22.4-dev6"), showCodeInRunModeAtom = atom(true);
65544
65545
  atom(null);
65545
65546
  var VIRTUAL_FILE_REGEX = /\/@file\/([^\s"&'/]+)\.([\dA-Za-z]+)/g, VirtualFileTracker = class e {
65546
65547
  constructor() {
@@ -25437,7 +25437,16 @@ ${n.sqlString}
25437
25437
  var _a2, _b2;
25438
25438
  let n = t.cellId;
25439
25439
  if (e.cellIds.hasOnlyOneId()) return e;
25440
- let r = e.cellIds.findWithId(n), i = r.indexOfOrThrow(n), a = i === 0 ? 1 : i - 1, o = null;
25440
+ let r;
25441
+ try {
25442
+ r = e.cellIds.findWithId(n);
25443
+ } catch (t2) {
25444
+ return Logger.warn("Skipping delete for missing cellId", {
25445
+ cellId: n,
25446
+ error: t2
25447
+ }), e;
25448
+ }
25449
+ let i = r.indexOfOrThrow(n), a = i === 0 ? 1 : i - 1, o = null;
25441
25450
  r.length > 1 && (o = r.atOrThrow(a));
25442
25451
  let s = (_b2 = (_a2 = e.cellHandles[n].current) == null ? void 0 : _a2.editorView) == null ? void 0 : _b2.state.toJSON({
25443
25452
  history: historyField
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.22.4-dev2",
3
+ "version": "0.22.4-dev6",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -267,6 +267,34 @@ describe("applyTransactionChanges edge cases", () => {
267
267
  `);
268
268
  });
269
269
 
270
+ it("delete-cell for nonexistent cell does not crash subsequent changes", () => {
271
+ setup("a", "b", "c");
272
+ const [, b] = state.cellIds.inOrderIds;
273
+ // Simulate the scenario from the bug report: a delete-cell for a cell ID
274
+ // that was never added to the frontend, followed by a create-cell and
275
+ // a set-code update. The delete should be silently skipped, and the rest
276
+ // of the transaction should still apply.
277
+ apply([
278
+ { type: "delete-cell", cellId: cellId("nonexistent") },
279
+ {
280
+ type: "create-cell",
281
+ cellId: cellId("VrZA"),
282
+ code: "import altair as alt",
283
+ name: "",
284
+ config: { hide_code: true },
285
+ },
286
+ { type: "set-code", cellId: b, code: "updated" },
287
+ ]);
288
+ expect(pretty(state)).toMatchInlineSnapshot(`
289
+ "
290
+ 0: 'a'
291
+ 1: 'updated'
292
+ 2: 'c'
293
+ VrZA: 'import altair as alt' [hide_code]
294
+ "
295
+ `);
296
+ });
297
+
270
298
  it("empty changes is a no-op", () => {
271
299
  setup("a", "b");
272
300
  apply([]);
@@ -6,6 +6,7 @@ import { type Atom, atom, useAtom, useAtomValue } from "jotai";
6
6
  import { atomFamily, selectAtom, splitAtom } from "jotai/utils";
7
7
  import { createRef, type ReducerWithoutAction } from "react";
8
8
  import type { CellHandle } from "@/components/editor/notebook-cell";
9
+ import type { CollapsibleTree } from "@/utils/id-tree";
9
10
  import {
10
11
  type CellColumnId,
11
12
  type CellIndex,
@@ -578,7 +579,18 @@ const {
578
579
  return state;
579
580
  }
580
581
 
581
- const column = state.cellIds.findWithId(cellId);
582
+ let column: CollapsibleTree<CellId>;
583
+ try {
584
+ column = state.cellIds.findWithId(cellId);
585
+ } catch (error) {
586
+ // Expected for kernel-only cells or out-of-order transactions.
587
+ Logger.warn("Skipping delete for missing cellId", {
588
+ cellId,
589
+ error,
590
+ });
591
+ return state;
592
+ }
593
+
582
594
  const cellIndex = column.indexOfOrThrow(cellId);
583
595
  const focusIndex = cellIndex === 0 ? 1 : cellIndex - 1;
584
596
  let scrollKey: CellId | null = null;
@@ -21,17 +21,19 @@ import { BINDING_MANAGER, WIDGET_DEF_REGISTRY } from "./widget-binding";
21
21
  interface Data {
22
22
  jsUrl: string;
23
23
  jsHash: string;
24
+ modelId: WidgetModelId;
24
25
  }
25
26
 
26
27
  type AnyWidgetState = ModelState;
27
28
 
28
29
  /**
29
- * Initial value is a model_id reference.
30
- * The backend sends just { model_id: string } and the frontend
31
- * retrieves the actual state from the 'open' message.
30
+ * Value payload sent by the frontend on state updates.
31
+ *
32
+ * The initial value from the backend is empty — `model_id` is passed
33
+ * via immutable data attributes (`args`) so it survives value overwrites.
32
34
  */
33
35
  interface ModelIdRef {
34
- model_id: WidgetModelId;
36
+ model_id?: WidgetModelId;
35
37
  }
36
38
 
37
39
  export function useAnyWidgetModule(opts: { jsUrl: string; jsHash: string }) {
@@ -117,14 +119,14 @@ export const AnyWidgetPlugin = createPlugin<ModelIdRef>("marimo-anywidget")
117
119
  z.object({
118
120
  jsUrl: z.string(),
119
121
  jsHash: z.string(),
122
+ modelId: z.string().transform((v) => v as WidgetModelId),
120
123
  }),
121
124
  )
122
125
  .withFunctions({})
123
126
  .renderer((props) => <AnyWidgetSlot {...props} />);
124
127
 
125
128
  const AnyWidgetSlot = (props: IPluginProps<ModelIdRef, Data>) => {
126
- const { jsUrl, jsHash } = props.data;
127
- const { model_id: modelId } = props.value;
129
+ const { jsUrl, jsHash, modelId } = props.data;
128
130
  const host = props.host as HTMLElementNotDerivedFromRef;
129
131
 
130
132
  const { jsModule, error } = useAnyWidgetModule({ jsUrl, jsHash });
@@ -29,6 +29,7 @@ describe("LoadedSlot", () => {
29
29
  data: {
30
30
  jsUrl: "http://example.com/widget.js",
31
31
  jsHash: "abc123",
32
+ modelId: modelId,
32
33
  },
33
34
  host: document.createElement(
34
35
  "div",
@@ -67,6 +68,30 @@ describe("LoadedSlot", () => {
67
68
  });
68
69
  });
69
70
 
71
+ it("should not remount when value update drops model_id", async () => {
72
+ // Regression: when the frontend sends a state update (e.g. {zoom_level: 0}),
73
+ // it overwrites the UIElement value that originally held {model_id: "..."}.
74
+ // The key must stay stable because modelId comes from data, not value.
75
+ const { container, rerender } = render(<LoadedSlot {...mockProps} />);
76
+
77
+ await waitFor(() => {
78
+ expect(mockWidget.render).toHaveBeenCalledTimes(1);
79
+ });
80
+
81
+ const divBefore = container.querySelector("div");
82
+
83
+ // Simulate a value update that does NOT include model_id
84
+ // (this is what happens when the widget sends trait state)
85
+ rerender(<LoadedSlot {...mockProps} />);
86
+
87
+ await waitFor(() => {
88
+ // The div should be the same DOM node (no remount)
89
+ expect(container.querySelector("div")).toBe(divBefore);
90
+ // render should not be called again (no remount)
91
+ expect(mockWidget.render).toHaveBeenCalledTimes(1);
92
+ });
93
+ });
94
+
70
95
  it("should re-run widget when widget prop changes", async () => {
71
96
  const { rerender } = render(<LoadedSlot {...mockProps} />);
72
97