@marimo-team/islands 0.19.10-dev12 → 0.19.10-dev15

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/main.js CHANGED
@@ -73304,7 +73304,7 @@ Image URL: ${r.imageUrl}`)), contextToXml({
73304
73304
  return Logger.warn("Failed to get version from mount config"), null;
73305
73305
  }
73306
73306
  }
73307
- const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.19.10-dev12"), showCodeInRunModeAtom = atom(true);
73307
+ const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.19.10-dev15"), showCodeInRunModeAtom = atom(true);
73308
73308
  atom(null);
73309
73309
  var import_compiler_runtime$88 = require_compiler_runtime();
73310
73310
  function useKeydownOnElement(e, r) {
@@ -74313,9 +74313,9 @@ Image URL: ${r.imageUrl}`)), contextToXml({
74313
74313
  ]
74314
74314
  }),
74315
74315
  (0, import_jsx_runtime.jsxs)("form", {
74316
- onSubmit: async (e2) => {
74317
- e2.preventDefault();
74318
- let c2 = y ? await convertToFileUIPart(y) : void 0;
74316
+ onSubmit: async (c2) => {
74317
+ if (c2.preventDefault(), e.disabled) return;
74318
+ let d2 = y ? await convertToFileUIPart(y) : void 0;
74319
74319
  RY({
74320
74320
  role: "user",
74321
74321
  parts: [
@@ -74323,12 +74323,13 @@ Image URL: ${r.imageUrl}`)), contextToXml({
74323
74323
  type: "text",
74324
74324
  text: r
74325
74325
  },
74326
- ...c2 ?? []
74326
+ ...d2 ?? []
74327
74327
  ]
74328
74328
  }), ZY();
74329
74329
  },
74330
74330
  ref: E,
74331
- className: "flex w-full border-t border-(--slate-6) px-2 py-1 items-center",
74331
+ inert: e.disabled || void 0,
74332
+ className: cn("flex w-full border-t border-(--slate-6) px-2 py-1 items-center", e.disabled && "opacity-50 cursor-not-allowed"),
74332
74333
  children: [
74333
74334
  e.showConfigurationControls && (0, import_jsx_runtime.jsx)(ConfigPopup, {
74334
74335
  config: d,
@@ -74745,7 +74746,8 @@ Image URL: ${r.imageUrl}`)), contextToXml({
74745
74746
  allowAttachments: union([
74746
74747
  boolean$2(),
74747
74748
  string$2().array()
74748
- ])
74749
+ ]),
74750
+ disabled: boolean$2().default(false)
74749
74751
  })).withFunctions({
74750
74752
  get_chat_history: rpc.input(object$1({})).output(object$1({
74751
74753
  messages: messageSchema
@@ -74767,6 +74769,7 @@ Image URL: ${r.imageUrl}`)), contextToXml({
74767
74769
  showConfigurationControls: e.data.showConfigurationControls,
74768
74770
  maxHeight: e.data.maxHeight,
74769
74771
  allowAttachments: e.data.allowAttachments,
74772
+ disabled: e.data.disabled,
74770
74773
  config: e.data.config,
74771
74774
  get_chat_history: e.functions.get_chat_history,
74772
74775
  delete_chat_history: e.functions.delete_chat_history,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.19.10-dev12",
3
+ "version": "0.19.10-dev15",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -140,6 +140,24 @@ def _(
140
140
  expect(extractCells(input)).toEqual(["x = a + b + c"]);
141
141
  });
142
142
 
143
+ it("preserves return statements inside nested functions", () => {
144
+ const input = `
145
+ @app.cell
146
+ def _(mo, px):
147
+ def make_fig():
148
+ data = {'category': ['foo', 'bar'], 'value': [10, 20]}
149
+ fig = px.bar(data, x='category', y='value')
150
+ return fig
151
+
152
+ fig = make_fig()
153
+ mo.ui.plotly(fig)
154
+ return
155
+ `;
156
+ expect(extractCells(input)).toEqual([
157
+ "def make_fig():\n data = {'category': ['foo', 'bar'], 'value': [10, 20]}\n fig = px.bar(data, x='category', y='value')\n return fig\n\nfig = make_fig()\nmo.ui.plotly(fig)",
158
+ ]);
159
+ });
160
+
143
161
  it("handles cells with config", () => {
144
162
  const input = `
145
163
  @app.cell(hide_code=True, column=2)
@@ -42,6 +42,7 @@ export function extractCells(text: string): string[] {
42
42
  let inMultilineArgs = false;
43
43
  let inMultilineReturn = false;
44
44
  let parenCount = 0;
45
+ let cellBaseIndent: number | null = null;
45
46
 
46
47
  // Pre-compile regex patterns
47
48
  const leadingParenRegex = /\(/g;
@@ -55,19 +56,16 @@ export function extractCells(text: string): string[] {
55
56
  );
56
57
  }
57
58
 
59
+ function getIndent(line: string): number {
60
+ const match = line.match(/^\s*/);
61
+ return match ? match[0].length : 0;
62
+ }
63
+
58
64
  function finalizeCellIfNeeded() {
59
65
  if (currentCell.length === 0) {
60
66
  return;
61
67
  }
62
68
 
63
- // Remove trailing returns
64
- while (
65
- currentCell.length > 0 &&
66
- currentCell[currentCell.length - 1].trim().startsWith("return")
67
- ) {
68
- currentCell.pop();
69
- }
70
-
71
69
  // Only add non-empty cells
72
70
  if (currentCell.some((l) => l.trim() !== "")) {
73
71
  cells.push(dedent(currentCell.join("\n")));
@@ -88,6 +86,7 @@ export function extractCells(text: string): string[] {
88
86
  finalizeCellIfNeeded();
89
87
  inCell = true;
90
88
  skipLines = 1; // Skip the def line
89
+ cellBaseIndent = null;
91
90
  continue;
92
91
  }
93
92
 
@@ -125,8 +124,13 @@ export function extractCells(text: string): string[] {
125
124
  continue;
126
125
  }
127
126
 
128
- // Handle return statements
129
- if (trimmed.startsWith("return")) {
127
+ // Detect base indentation of cell body from first content line
128
+ if (cellBaseIndent === null && trimmed) {
129
+ cellBaseIndent = getIndent(line);
130
+ }
131
+
132
+ // Handle return statements — only strip cell-level returns
133
+ if (trimmed.startsWith("return") && getIndent(line) === cellBaseIndent) {
130
134
  if (trimmed.includes("(") && !trimmed.endsWith(")")) {
131
135
  inMultilineReturn = true;
132
136
  parenCount = countParens(trimmed);
@@ -47,6 +47,7 @@ export const ChatPlugin = createPlugin<{ messages: UIMessage[] }>(
47
47
  maxHeight: z.number().optional(),
48
48
  config: configSchema,
49
49
  allowAttachments: z.union([z.boolean(), z.string().array()]),
50
+ disabled: z.boolean().default(false),
50
51
  }),
51
52
  )
52
53
  .withFunctions<PluginFunctions>({
@@ -76,6 +77,7 @@ export const ChatPlugin = createPlugin<{ messages: UIMessage[] }>(
76
77
  showConfigurationControls={props.data.showConfigurationControls}
77
78
  maxHeight={props.data.maxHeight}
78
79
  allowAttachments={props.data.allowAttachments}
80
+ disabled={props.data.disabled}
79
81
  config={props.data.config}
80
82
  get_chat_history={props.functions.get_chat_history}
81
83
  delete_chat_history={props.functions.delete_chat_history}
@@ -67,6 +67,7 @@ interface Props extends PluginFunctions {
67
67
  showConfigurationControls: boolean;
68
68
  maxHeight: number | undefined;
69
69
  allowAttachments: boolean | string[];
70
+ disabled: boolean;
70
71
  value: UIMessage[];
71
72
  setValue: (messages: UIMessage[]) => void;
72
73
  host: HTMLElement;
@@ -450,6 +451,9 @@ export const Chatbot: React.FC<Props> = (props) => {
450
451
  <form
451
452
  onSubmit={async (evt) => {
452
453
  evt.preventDefault();
454
+ if (props.disabled) {
455
+ return;
456
+ }
453
457
 
454
458
  const fileParts = files
455
459
  ? await convertToFileUIPart(files)
@@ -462,7 +466,12 @@ export const Chatbot: React.FC<Props> = (props) => {
462
466
  resetInput();
463
467
  }}
464
468
  ref={formRef}
465
- className="flex w-full border-t border-(--slate-6) px-2 py-1 items-center"
469
+ // biome-ignore lint/a11y/useSemanticElements: inert is used to disable the entire form
470
+ inert={props.disabled || undefined}
471
+ className={cn(
472
+ "flex w-full border-t border-(--slate-6) px-2 py-1 items-center",
473
+ props.disabled && "opacity-50 cursor-not-allowed",
474
+ )}
466
475
  >
467
476
  {props.showConfigurationControls && (
468
477
  <ConfigPopup config={config} onChange={setConfig} />