@marimo-team/islands 0.23.14-dev2 → 0.23.14-dev23

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.
Files changed (79) hide show
  1. package/dist/{ConnectedDataExplorerComponent-Du3_nUzI.js → ConnectedDataExplorerComponent-DXBx_nQg.js} +4 -4
  2. package/dist/{chat-ui-CsPewo4h.js → chat-ui-CO8WuXGb.js} +3243 -3039
  3. package/dist/{code-visibility-CRYdBxcA.js → code-visibility-B3ntFQLc.js} +1115 -917
  4. package/dist/{formats-d6MhLuQ9.js → formats-WsOgyW_K.js} +1 -1
  5. package/dist/{glide-data-editor-DkzAInWG.js → glide-data-editor-qpmKyAPn.js} +2 -2
  6. package/dist/{html-to-image-DXwLcQ6l.js → html-to-image-DLSOS-bE.js} +2351 -2282
  7. package/dist/{input-CbEz_aj_.js → input-BSdZp5Ng.js} +1 -1
  8. package/dist/main.js +1139 -1071
  9. package/dist/{mermaid-CJW9vIyO.js → mermaid-D-HYBMEV.js} +2 -2
  10. package/dist/{process-output-C6_e1pT_.js → process-output-B9ysqk1y.js} +1 -1
  11. package/dist/{reveal-component-CbqUMhp8.js → reveal-component-C8j14RKU.js} +16 -16
  12. package/dist/{spec-Bv-XlYiv.js → spec-CnTgI25l.js} +1 -1
  13. package/dist/{toDate-D-l5s8nn.js → toDate-D1Z7ZXWh.js} +1 -1
  14. package/dist/{useAsyncData-1Dhzjfwf.js → useAsyncData-BMc8itk2.js} +1 -1
  15. package/dist/{useDeepCompareMemoize-CDWT3BDz.js → useDeepCompareMemoize-ZwmDBRDY.js} +1 -1
  16. package/dist/{useLifecycle-AHlswLw-.js → useLifecycle-CxffarYV.js} +1 -1
  17. package/dist/{useTheme-BrYvK-_A.js → useTheme-yGsGEk82.js} +26 -24
  18. package/dist/{vega-component-Pk6lyc_a.js → vega-component-BFJTyykA.js} +5 -5
  19. package/package.json +2 -2
  20. package/src/components/chat/acp/agent-panel.tsx +35 -1
  21. package/src/components/chat/chat-panel.tsx +68 -29
  22. package/src/components/data-table/__tests__/column-explorer.test.tsx +25 -0
  23. package/src/components/data-table/__tests__/column-visibility-dropdown.test.tsx +60 -3
  24. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +33 -12
  25. package/src/components/data-table/column-visibility-dropdown.tsx +15 -0
  26. package/src/components/editor/actions/useNotebookActions.tsx +2 -2
  27. package/src/components/editor/chrome/panels/snippets-panel.tsx +5 -2
  28. package/src/components/editor/chrome/wrapper/__tests__/useOpenAiAssistant.test.ts +36 -0
  29. package/src/components/editor/chrome/wrapper/footer-items/pyodide-status.tsx +6 -36
  30. package/src/components/editor/chrome/wrapper/useAiPanel.ts +3 -1
  31. package/src/components/editor/chrome/wrapper/useOpenAiAssistant.ts +88 -0
  32. package/src/components/editor/code/readonly-python-code.tsx +16 -2
  33. package/src/components/editor/errors/__tests__/auto-fix.test.ts +23 -0
  34. package/src/components/editor/errors/auto-fix.tsx +88 -34
  35. package/src/components/editor/errors/fix-mode.ts +1 -1
  36. package/src/components/editor/output/MarimoTracebackOutput.tsx +10 -1
  37. package/src/components/editor/output/__tests__/traceback.test.tsx +14 -6
  38. package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +6 -2
  39. package/src/components/lifecycle/ProgressiveBoundary.tsx +42 -0
  40. package/src/components/lifecycle/RuntimeStatusBadge.tsx +59 -0
  41. package/src/components/lifecycle/__tests__/ProgressiveBoundary.test.tsx +147 -0
  42. package/src/components/lifecycle/__tests__/RuntimeStatusBadge.test.tsx +72 -0
  43. package/src/components/slides/slide-cell-view.tsx +7 -6
  44. package/src/core/ai/config.ts +2 -2
  45. package/src/core/ai/context/__tests__/registry.test.ts +133 -3
  46. package/src/core/ai/context/providers/__tests__/datasource.test.ts +3 -1
  47. package/src/core/ai/context/providers/__tests__/error.test.ts +200 -15
  48. package/src/core/ai/context/providers/datasource.ts +27 -2
  49. package/src/core/ai/context/providers/error.ts +226 -36
  50. package/src/core/ai/context/registry.ts +77 -43
  51. package/src/core/ai/state.ts +11 -0
  52. package/src/core/cells/__tests__/readonly-code-display.test.ts +46 -0
  53. package/src/core/cells/readonly-code-display.ts +35 -0
  54. package/src/core/codemirror/__tests__/setup.test.ts +33 -1
  55. package/src/core/codemirror/ai/resources.ts +15 -10
  56. package/src/core/codemirror/cells/extensions.ts +1 -4
  57. package/src/core/codemirror/completion/__tests__/signature-hint.test.ts +94 -0
  58. package/src/core/codemirror/completion/completer.ts +12 -1
  59. package/src/core/codemirror/completion/signature-hint.ts +68 -0
  60. package/src/core/codemirror/language/languages/python.ts +10 -4
  61. package/src/core/codemirror/utils.ts +15 -0
  62. package/src/core/edit-app.tsx +8 -5
  63. package/src/core/errors/errors.ts +2 -1
  64. package/src/core/lifecycle/__tests__/render-policy.test.ts +247 -0
  65. package/src/core/lifecycle/render-policy.ts +125 -0
  66. package/src/core/mime.ts +11 -4
  67. package/src/core/run-app.tsx +27 -23
  68. package/src/core/runtime/__tests__/adapter.test.ts +160 -0
  69. package/src/core/runtime/adapter.ts +182 -0
  70. package/src/core/wasm/PyodideLoader.tsx +20 -62
  71. package/src/core/wasm/bridge.ts +9 -4
  72. package/src/core/wasm/state.ts +8 -19
  73. package/src/core/wasm/store.ts +1 -1
  74. package/src/hooks/__tests__/useDelayElapsed.test.tsx +55 -0
  75. package/src/hooks/useDelayElapsed.ts +27 -0
  76. package/src/core/ai/context/providers/__tests__/__snapshots__/error.test.ts.snap +0 -3
  77. package/src/core/wasm/__tests__/PyodideLoader.test.ts +0 -72
  78. package/src/core/wasm/__tests__/state.test.ts +0 -124
  79. /package/dist/{files → export_demos}/wasm-intro.py +0 -0
@@ -7,9 +7,9 @@ import { t as require_jsx_runtime } from "./jsx-runtime-DebpN0FN.js";
7
7
  import "./zod-CijjQh4u.js";
8
8
  import { n as ErrorBanner } from "./error-banner-DFPfz_Qf.js";
9
9
  import { t as isEmpty_default } from "./isEmpty-CJJMn-QP.js";
10
- import { n as useTheme } from "./useTheme-BrYvK-_A.js";
10
+ import { n as useTheme } from "./useTheme-yGsGEk82.js";
11
11
  import { t as purify } from "./purify.es-H92eMd9-.js";
12
- import { t as useAsyncData } from "./useAsyncData-1Dhzjfwf.js";
12
+ import { t as useAsyncData } from "./useAsyncData-BMc8itk2.js";
13
13
  import { a as decodeEntities, f as isDetailedError, g as utils_default, h as removeDirectives, i as cleanAndMerge, o as encodeEntities } from "./chunk-S3R3BYOJ-oAe3dEbO.js";
14
14
  import { a as setLogLevel, i as log, r as __name, t as select_default } from "./src-Bf2iLOlr.js";
15
15
  import { t as package_default } from "./chunk-DR5Q36YT-BflwErH1.js";
@@ -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-DXwLcQ6l.js";
3
+ import { at as parseHtmlContent, it as ansiToPlainText } from "./html-to-image-DLSOS-bE.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,17 +6,17 @@ 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-DXwLcQ6l.js";
9
+ import { lt as kioskModeAtom } from "./html-to-image-DLSOS-bE.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, an as EyeOff, c as Slide, ct as PanelResizeHandle, i as DEFAULT_DECK_TRANSITION, ln as Code, on as Expand, ot as Panel, s as SlideSidebar, st as PanelGroup, t as useNotebookCodeAvailable } from "./code-visibility-CRYdBxcA.js";
13
- import { X as useDebouncedCallback } from "./input-CbEz_aj_.js";
14
- import "./toDate-D-l5s8nn.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-B3ntFQLc.js";
13
+ import { X as useDebouncedCallback } from "./input-BSdZp5Ng.js";
14
+ import "./toDate-D1Z7ZXWh.js";
15
15
  import "./react-dom-BTJzcVJ9.js";
16
16
  import { t as require_jsx_runtime } from "./jsx-runtime-DebpN0FN.js";
17
17
  import { X as useFullScreenElement } from "./zod-CijjQh4u.js";
18
18
  import { t as Tooltip } from "./tooltip-Czds6Qr8.js";
19
- import { T as useEvent_default, _ as useAtomValue, m as isIslands } from "./useTheme-BrYvK-_A.js";
19
+ import { D as useEvent_default, g as isIslands, y as useAtomValue } from "./useTheme-yGsGEk82.js";
20
20
  import "./dist-U4F-tbMs.js";
21
21
  import "./main-Tj_-QTyF.js";
22
22
  import "./dist-Dv_Y15yk.js";
@@ -7245,12 +7245,12 @@ function _temp(e5) {
7245
7245
  };
7246
7246
  }
7247
7247
  var SubslideView = (e5) => {
7248
- let t = (0, import_compiler_runtime.c)(24), { subslide: n, resolveShowCode: r, isEditable: i, slideConfigs: a } = e5, o, s, c, l, u, f;
7248
+ let t = (0, import_compiler_runtime.c)(24), { subslide: n, resolveShowCode: r, isEditable: i, slideConfigs: a } = e5, o, s, c, l, u, ro;
7249
7249
  if (t[0] !== i || t[1] !== r || t[2] !== a || t[3] !== n) {
7250
7250
  let { slideLevel: e6, cumulativeByBlock: io2 } = buildSubslideNotes(n, a);
7251
7251
  s = e6;
7252
7252
  let p2 = n.blocks.some((e7) => e7.cells.some((e8) => r(e8.id)));
7253
- o = w, f = "h-full w-full overflow-auto flex", c = p2 ? "mo-slide-content flex flex-col gap-3" : "mo-slide-content", t[10] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (l = { margin: "auto 20px" }, t[10] = l) : l = t[10], u = n.blocks.map((e7, t2) => {
7253
+ o = w, ro = "h-full w-full overflow-auto flex", c = p2 ? "mo-slide-content flex flex-col gap-3" : "mo-slide-content", t[10] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (l = { margin: "auto 20px" }, t[10] = l) : l = t[10], u = n.blocks.map((e7, t2) => {
7254
7254
  let n2 = e7.cells.map((e8) => r(e8.id) ? i ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SlideCellView, { cell: e8 }, e8.id) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SlideCellReadOnlyView, { cell: e8 }, e8.id) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Slide, {
7255
7255
  cellId: e8.id,
7256
7256
  status: e8.status,
@@ -7264,8 +7264,8 @@ var SubslideView = (e5) => {
7264
7264
  }, t2);
7265
7265
  }
7266
7266
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Fragment, { children: n2 }, t2);
7267
- }), t[0] = i, t[1] = r, t[2] = a, t[3] = n, t[4] = o, t[5] = s, t[6] = c, t[7] = l, t[8] = u, t[9] = f;
7268
- } else o = t[4], s = t[5], c = t[6], l = t[7], u = t[8], f = t[9];
7267
+ }), t[0] = i, t[1] = r, t[2] = a, t[3] = n, t[4] = o, t[5] = s, t[6] = c, t[7] = l, t[8] = u, t[9] = ro;
7268
+ } else o = t[4], s = t[5], c = t[6], l = t[7], u = t[8], ro = t[9];
7269
7269
  let io;
7270
7270
  t[11] !== c || t[12] !== l || t[13] !== u ? (io = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
7271
7271
  className: c,
@@ -7273,10 +7273,10 @@ var SubslideView = (e5) => {
7273
7273
  children: u
7274
7274
  }), t[11] = c, t[12] = l, t[13] = u, t[14] = io) : io = t[14];
7275
7275
  let p;
7276
- t[15] !== f || t[16] !== io ? (p = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
7277
- className: f,
7276
+ t[15] !== ro || t[16] !== io ? (p = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
7277
+ className: ro,
7278
7278
  children: io
7279
- }), t[15] = f, t[16] = io, t[17] = p) : p = t[17];
7279
+ }), t[15] = ro, t[16] = io, t[17] = p) : p = t[17];
7280
7280
  let ao;
7281
7281
  t[18] === s ? ao = t[19] : (ao = s && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NotesAside, { text: s }), t[18] = s, t[19] = ao);
7282
7282
  let oo;
@@ -7302,7 +7302,7 @@ var ParkedPreviewContent = (e5) => {
7302
7302
  status: n.status,
7303
7303
  output: n.output
7304
7304
  }), t[3] = n.id, t[4] = n.output, t[5] = n.status, t[6] = o) : o = t[6], o;
7305
- }, reveal_component_default = ({ slideCells: e5, layout: o, setLayout: s, noOutputIds: l, activeIndex: u, onSlideChange: ro, mode: p, configWidth: fo, isEditable: po = false }) => {
7305
+ }, reveal_component_default = ({ slideCells: e5, layout: o, setLayout: s, noOutputIds: l, activeIndex: u, onSlideChange: f, mode: io, configWidth: fo, isEditable: po = false }) => {
7306
7306
  var _a2, _b2;
7307
7307
  let yo = (0, import_react.useRef)(null), bo = (0, import_react.useRef)(null), { width: So, height: Co } = useSlideDimensions(yo), wo = useFullScreenElement() != null, To = useAtomValue(kioskModeAtom), Eo = (0, import_react.useMemo)(() => To ? [] : [ce], [To]), [Do, Oo] = (0, import_react.useState)(() => /* @__PURE__ */ new Set()), ko = useNotebookCodeAvailable(e5), Ao = !isIslands() && ko, jo = u == null ? void 0 : e5[u], Mo = jo ?? e5.at(0), { parkedPreviewCell: No, isHeldEdit: Po, isNoOutputPreview: Fo, heldEditCellId: Io, heldShowsCode: Lo, toggleHeldShowsCode: Ro } = useParkedPreview({
7308
7308
  activeCell: jo,
@@ -7391,14 +7391,14 @@ var ParkedPreviewContent = (e5) => {
7391
7391
  let e6 = bo.current;
7392
7392
  if (!e6) return;
7393
7393
  let t = resolveActiveCellIndex(Go, e6.getIndices());
7394
- t != null && (ro == null ? void 0 : ro(t));
7394
+ t != null && (f == null ? void 0 : f(t));
7395
7395
  }), $o = useEvent_default((t) => {
7396
7396
  if (!No || u == null || Events.fromInput(t)) return;
7397
7397
  let n = classifyNavKey(t);
7398
7398
  if (n === 0) return;
7399
7399
  t.preventDefault(), t.stopPropagation();
7400
7400
  let i = u + n;
7401
- i < 0 || i >= e5.length || (ro == null ? void 0 : ro(i));
7401
+ i < 0 || i >= e5.length || (f == null ? void 0 : f(i));
7402
7402
  }), ns = useEvent_default(() => {
7403
7403
  Qo(), triggerResize(bo.current);
7404
7404
  });
@@ -7494,7 +7494,7 @@ var ParkedPreviewContent = (e5) => {
7494
7494
  ]
7495
7495
  })
7496
7496
  });
7497
- return p === "read" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
7497
+ return io === "read" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
7498
7498
  className: "flex-1 min-w-0 flex flex-row gap-3",
7499
7499
  children: os
7500
7500
  }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
@@ -1,5 +1,5 @@
1
1
  import { u as createLucideIcon } from "./dist--2Bqjvs0.js";
2
- import { s as Hash } from "./useLifecycle-AHlswLw-.js";
2
+ import { s as Hash } from "./useLifecycle-CxffarYV.js";
3
3
  import { i as Table, o as ChartPie } from "./useDateFormatter-CMnRuVmN.js";
4
4
  import { C as logNever } from "./strings-Dq_j3Rxw.js";
5
5
  var AlignCenterVertical = createLucideIcon("align-center-vertical", [
@@ -6,7 +6,7 @@ import { _ as Logger } from "./button-BacYv-bE.js";
6
6
  import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
7
7
  import { u as createLucideIcon } from "./dist--2Bqjvs0.js";
8
8
  import { r as KnownQueryParams } from "./constants-T20xxyNf.js";
9
- import { b as atom, d as store, m as isIslands, p as waitFor } from "./useTheme-BrYvK-_A.js";
9
+ import { S as atom, g as isIslands, h as waitFor, p as store } from "./useTheme-yGsGEk82.js";
10
10
  import { t as invariant } from "./invariant-wRzNXIsJ.js";
11
11
  var CircleQuestionMark = createLucideIcon("circle-question-mark", [
12
12
  ["circle", {
@@ -1,7 +1,7 @@
1
1
  import { s as __toESM } from "./chunk-BNovOVIE.js";
2
2
  import { t as require_react } from "./react-DA-nE2FX.js";
3
3
  import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
4
- import { T as useEvent_default } from "./useTheme-BrYvK-_A.js";
4
+ import { D as useEvent_default } from "./useTheme-yGsGEk82.js";
5
5
  import { t as invariant } from "./invariant-wRzNXIsJ.js";
6
6
  var import_compiler_runtime = require_compiler_runtime(), import_react = /* @__PURE__ */ __toESM(require_react(), 1), Result = {
7
7
  error(e, s) {
@@ -1,6 +1,6 @@
1
1
  import { s as __toESM } from "./chunk-BNovOVIE.js";
2
2
  import { t as require_react } from "./react-DA-nE2FX.js";
3
- import { w as dequal } from "./useTheme-BrYvK-_A.js";
3
+ import { E as dequal } from "./useTheme-yGsGEk82.js";
4
4
  var import_react = /* @__PURE__ */ __toESM(require_react(), 1);
5
5
  function useDeepCompareMemoize(e) {
6
6
  let i = import_react.useRef(e);
@@ -4,7 +4,7 @@ import { t as require_react } from "./react-DA-nE2FX.js";
4
4
  import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
5
5
  import { u as createLucideIcon } from "./dist--2Bqjvs0.js";
6
6
  import { t as require_jsx_runtime } from "./jsx-runtime-DebpN0FN.js";
7
- import { b as atom, v as useSetAtom } from "./useTheme-BrYvK-_A.js";
7
+ import { S as atom, b as useSetAtom } from "./useTheme-yGsGEk82.js";
8
8
  var Calendar = createLucideIcon("calendar", [
9
9
  ["path", {
10
10
  d: "M8 2v4",
@@ -709,8 +709,8 @@ function useResolvedMarimoConfig() {
709
709
  function getResolvedMarimoConfig() {
710
710
  return store.get(resolvedMarimoConfigAtom);
711
711
  }
712
- atom((e) => isAiEnabled(e(resolvedMarimoConfigAtom))), atom((e) => isAiModelConfigured(e(resolvedMarimoConfigAtom)));
713
- const aiFeaturesEnabledAtom = atom((e) => isAiFeatureEnabled(e(resolvedMarimoConfigAtom)));
712
+ atom((e) => isAiEnabled(e(resolvedMarimoConfigAtom)));
713
+ const aiModelConfiguredAtom = atom((e) => isAiModelConfigured(e(resolvedMarimoConfigAtom))), aiFeaturesEnabledAtom = atom((e) => isAiFeatureEnabled(e(resolvedMarimoConfigAtom)));
714
714
  atom((e) => e(resolvedMarimoConfigAtom).display.code_editor_font_size);
715
715
  const localeAtom = atom((e) => e(resolvedMarimoConfigAtom).display.locale);
716
716
  function isAiEnabled(e) {
@@ -790,29 +790,31 @@ function useTheme() {
790
790
  return e[1] === j ? M = e[2] : (M = { theme: j }, e[1] = j, e[2] = M), M;
791
791
  }
792
792
  export {
793
- getBuildingBlocks as C,
794
- buildStore as S,
795
- useEvent_default as T,
796
- useAtomValue as _,
797
- getResolvedMarimoConfig as a,
798
- atom as b,
799
- useResolvedMarimoConfig as c,
800
- store as d,
801
- useJotaiEffect as f,
802
- useAtom as g,
803
- Provider as h,
804
- autoInstantiateAtom as i,
805
- AppConfigSchema as l,
806
- isIslands as m,
793
+ createStore as C,
794
+ useEvent_default as D,
795
+ dequal as E,
796
+ atom as S,
797
+ getBuildingBlocks as T,
798
+ Provider as _,
799
+ autoInstantiateAtom as a,
800
+ useSetAtom as b,
801
+ resolvedMarimoConfigAtom as c,
802
+ AppConfigSchema as d,
803
+ createDeepEqualAtom as f,
804
+ isIslands as g,
805
+ waitFor as h,
806
+ aiModelConfiguredAtom as i,
807
+ useResolvedMarimoConfig as l,
808
+ useJotaiEffect as m,
807
809
  useTheme as n,
808
- localeAtom as o,
809
- waitFor as p,
810
+ getResolvedMarimoConfig as o,
811
+ store as p,
810
812
  aiFeaturesEnabledAtom as r,
811
- resolvedMarimoConfigAtom as s,
813
+ localeAtom as s,
812
814
  resolvedThemeAtom as t,
813
- createDeepEqualAtom as u,
814
- useSetAtom as v,
815
- dequal as w,
816
- createStore as x,
817
- useStore as y
815
+ userConfigAtom as u,
816
+ useAtom as v,
817
+ buildStore as w,
818
+ useStore as x,
819
+ useAtomValue as y
818
820
  };
@@ -2,23 +2,23 @@ import { s as __toESM } from "./chunk-BNovOVIE.js";
2
2
  import { _ as Logger, c as Objects, g as cn, h as Events } from "./button-BacYv-bE.js";
3
3
  import { t as require_react } from "./react-DA-nE2FX.js";
4
4
  import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
5
- import { c as asRemoteURL, v as CircleQuestionMark } from "./toDate-D-l5s8nn.js";
5
+ import { c as asRemoteURL, v as CircleQuestionMark } from "./toDate-D1Z7ZXWh.js";
6
6
  import "./react-dom-BTJzcVJ9.js";
7
7
  import { t as require_jsx_runtime } from "./jsx-runtime-DebpN0FN.js";
8
8
  import "./zod-CijjQh4u.js";
9
9
  import { n as ErrorBanner } from "./error-banner-DFPfz_Qf.js";
10
10
  import { t as Tooltip } from "./tooltip-Czds6Qr8.js";
11
11
  import { i as debounce_default } from "./constants-T20xxyNf.js";
12
- import { T as useEvent_default, n as useTheme } from "./useTheme-BrYvK-_A.js";
12
+ import { D as useEvent_default, n as useTheme } from "./useTheme-yGsGEk82.js";
13
13
  import { s as uniq } from "./arrays-sEtDRoG4.js";
14
- import { a as isValid, i as AlertTitle, n as Alert, t as arrow } from "./formats-d6MhLuQ9.js";
14
+ import { a as isValid, i as AlertTitle, n as Alert, t as arrow } from "./formats-WsOgyW_K.js";
15
15
  import { n as formats } from "./vega-loader.browser-CZ-J8Py3.js";
16
16
  import { a as getContainerWidth, n as vegaLoadData, s as tooltipHandler } from "./loader-Boph2xIS.js";
17
17
  import { t as j } from "./react-vega-B0sAlDTL.js";
18
18
  import "./defaultLocale-u-3osm0P.js";
19
19
  import "./defaultLocale-BoHTsDG6.js";
20
- import { t as useAsyncData } from "./useAsyncData-1Dhzjfwf.js";
21
- import { t as useDeepCompareMemoize } from "./useDeepCompareMemoize-CDWT3BDz.js";
20
+ import { t as useAsyncData } from "./useAsyncData-BMc8itk2.js";
21
+ import { t as useDeepCompareMemoize } from "./useDeepCompareMemoize-ZwmDBRDY.js";
22
22
  import { t as Semaphore } from "./semaphore-CNDGTzkX.js";
23
23
  var import_compiler_runtime = require_compiler_runtime(), import_react = /* @__PURE__ */ __toESM(require_react(), 1);
24
24
  function fixRelativeUrl(e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.23.14-dev2",
3
+ "version": "0.23.14-dev23",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -56,7 +56,7 @@
56
56
  "@lezer/python": "^1.1.18",
57
57
  "@marimo-team/codemirror-ai": "^0.3.7",
58
58
  "@marimo-team/codemirror-languageserver": "^1.16.12",
59
- "@marimo-team/codemirror-mcp": "^0.1.5",
59
+ "@marimo-team/codemirror-mcp": "^0.1.7",
60
60
  "@marimo-team/codemirror-sql": "^0.2.8",
61
61
  "@marimo-team/llm-info": "workspace:*",
62
62
  "@marimo-team/marimo-api": "workspace:*",
@@ -49,6 +49,7 @@ import {
49
49
  addContextCompletion,
50
50
  CONTEXT_TRIGGER,
51
51
  } from "@/components/editor/ai/completion-utils";
52
+ import { pendingAiPromptAtom } from "@/core/ai/state";
52
53
  import {
53
54
  Select,
54
55
  SelectContent,
@@ -72,6 +73,7 @@ import {
72
73
  SendButton,
73
74
  } from "../chat-components";
74
75
  import { useFileState } from "../chat-utils";
76
+ import { focusInputAndMoveToEnd } from "@/core/codemirror/utils";
75
77
  import { ReadyToChatBlock } from "./blocks";
76
78
  import {
77
79
  convertFilesToResourceLinks,
@@ -305,6 +307,7 @@ interface PromptAreaProps {
305
307
  onModeChange?: (mode: string) => void;
306
308
  sessionModels?: SessionModelState | null;
307
309
  onModelChange?: (modelId: string) => void;
310
+ inputRef: React.RefObject<ReactCodeMirrorRef | null>;
308
311
  }
309
312
 
310
313
  const PromptArea = memo<PromptAreaProps>(
@@ -322,8 +325,8 @@ const PromptArea = memo<PromptAreaProps>(
322
325
  onModeChange,
323
326
  sessionModels,
324
327
  onModelChange,
328
+ inputRef,
325
329
  }) => {
326
- const inputRef = useRef<ReactCodeMirrorRef | null>(null);
327
330
  const promptCompletions: AdditionalCompletions | undefined = useMemo(() => {
328
331
  if (!commands) {
329
332
  return undefined;
@@ -660,6 +663,8 @@ const AgentPanel: React.FC = () => {
660
663
  const [isLoading, setIsLoading] = useState(false);
661
664
  const [error, setError] = useState<Error | string | null>(null);
662
665
  const [promptValue, setPromptValue] = useState("");
666
+ const promptInputRef = useRef<ReactCodeMirrorRef | null>(null);
667
+ const [pendingPrompt, setPendingPrompt] = useAtom(pendingAiPromptAtom);
663
668
  const { files, addFiles, clearFiles, removeFile } = useFileState();
664
669
  const [sessionModels, setSessionModels] = useState<SessionModelState | null>(
665
670
  null,
@@ -973,6 +978,34 @@ const AgentPanel: React.FC = () => {
973
978
  },
974
979
  );
975
980
 
981
+ // Consume a prompt queued by another part of the app (e.g. error auto-fix).
982
+ useEffect(() => {
983
+ if (
984
+ !activeSessionId ||
985
+ !agent ||
986
+ isLoading ||
987
+ connectionState.status !== "connected" ||
988
+ !pendingPrompt
989
+ ) {
990
+ return;
991
+ }
992
+ setPendingPrompt(null);
993
+ if (pendingPrompt.submit) {
994
+ void handlePromptSubmit(undefined, pendingPrompt.prompt);
995
+ } else {
996
+ setPromptValue(pendingPrompt.prompt);
997
+ focusInputAndMoveToEnd(promptInputRef);
998
+ }
999
+ }, [
1000
+ activeSessionId,
1001
+ agent,
1002
+ isLoading,
1003
+ connectionState.status,
1004
+ pendingPrompt,
1005
+ setPendingPrompt,
1006
+ handlePromptSubmit,
1007
+ ]);
1008
+
976
1009
  // Handler for stopping the current operation
977
1010
  const handleStop = useEvent(async () => {
978
1011
  if (!activeSessionId || !agent) {
@@ -1187,6 +1220,7 @@ const AgentPanel: React.FC = () => {
1187
1220
  onModeChange={handleModeChange}
1188
1221
  sessionModels={sessionModels}
1189
1222
  onModelChange={handleModelChange}
1223
+ inputRef={promptInputRef}
1190
1224
  />
1191
1225
  </>
1192
1226
  );
@@ -45,6 +45,7 @@ import {
45
45
  type Chat,
46
46
  type ChatId,
47
47
  chatStateAtom,
48
+ pendingAiPromptAtom,
48
49
  } from "@/core/ai/state";
49
50
  import type { ToolNotebookContext } from "@/core/ai/tools/base";
50
51
  import {
@@ -94,6 +95,7 @@ import {
94
95
  useFileState,
95
96
  } from "./chat-utils";
96
97
  import { getCodes } from "@/core/codemirror/copilot/getCodes";
98
+ import { focusInputAndMoveToEnd } from "@/core/codemirror/utils";
97
99
 
98
100
  // Default mode for the AI
99
101
  const DEFAULT_MODE = "manual";
@@ -407,6 +409,7 @@ const ChatInput: React.FC<ChatInputProps> = memo(
407
409
  <div className="relative shrink-0 min-h-[80px] flex flex-col border-t">
408
410
  <div className={cn("px-2 py-3 flex-1", inputClassName)}>
409
411
  <PromptInput
412
+ className="max-h-[400px]"
410
413
  inputRef={inputRef}
411
414
  value={input}
412
415
  onChange={setInput}
@@ -481,6 +484,7 @@ const ChatPanel = () => {
481
484
  const ChatPanelBody = () => {
482
485
  const setChatState = useSetAtom(chatStateAtom);
483
486
  const [activeChat, setActiveChat] = useAtom(activeChatAtom);
487
+ const [pendingPrompt, setPendingPrompt] = useAtom(pendingAiPromptAtom);
484
488
  const [input, setInput] = useState("");
485
489
  const [newThreadInput, setNewThreadInput] = useState("");
486
490
  const { files, addFiles, clearFiles, removeFile } = useFileState();
@@ -600,10 +604,7 @@ const ChatPanelBody = () => {
600
604
  requestAnimationFrame(scrollToBottom);
601
605
  }, [activeChatId]);
602
606
 
603
- const createNewThread = async (
604
- initialMessage: string,
605
- initialAttachments?: File[],
606
- ) => {
607
+ const startNewChatState = useEvent((initialMessage: string) => {
607
608
  const now = Date.now();
608
609
  const newChat: Chat = {
609
610
  id: chatId as ChatId,
@@ -613,41 +614,41 @@ const ChatPanelBody = () => {
613
614
  updatedAt: now,
614
615
  };
615
616
 
616
- // Create new chat and set as active
617
617
  setChatState((prev) => {
618
618
  const newChats = new Map(prev.chats);
619
619
  newChats.set(newChat.id, newChat);
620
- const newState = {
620
+ return {
621
621
  ...prev,
622
622
  chats: newChats,
623
623
  activeChatId: newChat.id,
624
624
  };
625
- return newState;
626
625
  });
626
+ });
627
627
 
628
- const fileParts =
629
- initialAttachments && initialAttachments.length > 0
630
- ? await convertToFileUIPart(initialAttachments)
631
- : undefined;
632
- const { contextPart, attachments } =
633
- await resolveChatContext(initialMessage);
628
+ const createNewThread = useEvent(
629
+ async (initialMessage: string, initialAttachments?: File[]) => {
630
+ startNewChatState(initialMessage);
634
631
 
635
- // Trigger AI conversation with append
636
- sendMessage({
637
- role: "user",
638
- parts: [
639
- {
640
- type: "text" as const,
641
- text: initialMessage,
642
- },
643
- ...(contextPart ? [contextPart] : []),
644
- ...(fileParts ?? []),
645
- ...attachments,
646
- ],
647
- });
648
- clearFiles();
649
- setInput("");
650
- };
632
+ const fileParts =
633
+ initialAttachments && initialAttachments.length > 0
634
+ ? await convertToFileUIPart(initialAttachments)
635
+ : undefined;
636
+ const { contextPart, attachments } =
637
+ await resolveChatContext(initialMessage);
638
+
639
+ sendMessage({
640
+ role: "user",
641
+ parts: [
642
+ { type: "text" as const, text: initialMessage },
643
+ ...(contextPart ? [contextPart] : []),
644
+ ...(fileParts ?? []),
645
+ ...attachments,
646
+ ],
647
+ });
648
+ clearFiles();
649
+ setInput("");
650
+ },
651
+ );
651
652
 
652
653
  const handleNewChat = useEvent(() => {
653
654
  setActiveChat(null);
@@ -728,7 +729,45 @@ const ChatPanelBody = () => {
728
729
 
729
730
  const handleOnCloseThread = () => newThreadInputRef.current?.editor?.blur();
730
731
 
732
+ const submitPendingPrompt = useEvent(async (prompt: string) => {
733
+ if (activeChatId == null) {
734
+ startNewChatState(prompt);
735
+ // Starting a chat swaps the new-thread input for the regular input;
736
+ // carry over any draft the user had typed so it isn't lost.
737
+ setInput(newThreadInput);
738
+ }
739
+ const { contextPart, attachments } = await resolveChatContext(prompt);
740
+ sendMessage({
741
+ role: "user",
742
+ parts: [
743
+ { type: "text", text: prompt },
744
+ ...(contextPart ? [contextPart] : []),
745
+ ...attachments,
746
+ ],
747
+ });
748
+ });
749
+
731
750
  const isNewThread = messages.length === 0;
751
+
752
+ // Deliver a prompt queued elsewhere (e.g. error auto-fix) to the chat,
753
+ // appending to the active thread or starting one if none exists.
754
+ useEffect(() => {
755
+ if (!pendingPrompt) {
756
+ return;
757
+ }
758
+ setPendingPrompt(null);
759
+ const { prompt, submit } = pendingPrompt;
760
+ if (submit) {
761
+ void submitPendingPrompt(prompt);
762
+ } else if (isNewThread) {
763
+ setNewThreadInput(prompt);
764
+ focusInputAndMoveToEnd(newThreadInputRef);
765
+ } else {
766
+ setInput(prompt);
767
+ focusInputAndMoveToEnd(newMessageInputRef);
768
+ }
769
+ }, [pendingPrompt, setPendingPrompt, isNewThread, submitPendingPrompt]);
770
+
732
771
  const chatInput = isNewThread ? (
733
772
  <ChatInput
734
773
  key="new-thread-input"
@@ -126,3 +126,28 @@ describe("ColumnExplorerPanel header counts", () => {
126
126
  expect(screen.queryByText(/hidden/)).not.toBeInTheDocument();
127
127
  });
128
128
  });
129
+
130
+ describe("ColumnExplorerPanel visibility actions", () => {
131
+ const showAll = () => screen.getByRole("button", { name: /Show all/ });
132
+ const hideAll = () => screen.getByRole("button", { name: /Hide all/ });
133
+
134
+ it("disables 'Show all' when every column is visible", () => {
135
+ renderPanel();
136
+ expect(showAll()).toBeDisabled();
137
+ expect(hideAll()).toBeEnabled();
138
+ });
139
+
140
+ it("disables 'Hide all' when every column is hidden", () => {
141
+ renderPanel({
142
+ initiallyHidden: ["customer_name", "cust_age", "order_total"],
143
+ });
144
+ expect(showAll()).toBeEnabled();
145
+ expect(hideAll()).toBeDisabled();
146
+ });
147
+
148
+ it("enables both actions when some columns are hidden", () => {
149
+ renderPanel({ initiallyHidden: ["cust_age"] });
150
+ expect(showAll()).toBeEnabled();
151
+ expect(hideAll()).toBeEnabled();
152
+ });
153
+ });
@@ -21,10 +21,17 @@ beforeAll(() => {
21
21
 
22
22
  type Row = Record<string, unknown>;
23
23
 
24
+ // Select, index, and nameless columns are non-hideable in production
25
+ // (see columns.tsx), so the harness mirrors that to keep visibility counts
26
+ // aligned with the real table.
24
27
  const TEST_COLUMNS: ColumnDef<Row>[] = [
25
- { id: SELECT_COLUMN_ID, accessorKey: SELECT_COLUMN_ID },
26
- { id: INDEX_COLUMN_NAME, accessorKey: INDEX_COLUMN_NAME },
27
- { id: "__m_column__0", accessorKey: "__m_column__0" },
28
+ { id: SELECT_COLUMN_ID, accessorKey: SELECT_COLUMN_ID, enableHiding: false },
29
+ {
30
+ id: INDEX_COLUMN_NAME,
31
+ accessorKey: INDEX_COLUMN_NAME,
32
+ enableHiding: false,
33
+ },
34
+ { id: "__m_column__0", accessorKey: "__m_column__0", enableHiding: false },
28
35
  {
29
36
  id: "customer_name",
30
37
  accessorKey: "customer_name",
@@ -101,6 +108,7 @@ describe("ColumnVisibilityDropdown", () => {
101
108
  renderAndOpen({ initiallyHidden: ["cust_age"] });
102
109
  expect(getOptionTexts()).toEqual([
103
110
  "Show all",
111
+ "Hide all",
104
112
  "cust_age",
105
113
  "customer_name",
106
114
  "order_total",
@@ -117,6 +125,7 @@ describe("ColumnVisibilityDropdown", () => {
117
125
 
118
126
  expect(getOptionTexts()).toEqual([
119
127
  "Show all",
128
+ "Hide all",
120
129
  "cust_age",
121
130
  "customer_name",
122
131
  "order_total",
@@ -132,6 +141,7 @@ describe("ColumnVisibilityDropdown", () => {
132
141
  fireEvent.click(getColumnOption("customer_name"));
133
142
  expect(getOptionTexts()).toEqual([
134
143
  "Show all",
144
+ "Hide all",
135
145
  "cust_age",
136
146
  "customer_name",
137
147
  "order_total",
@@ -144,6 +154,7 @@ describe("ColumnVisibilityDropdown", () => {
144
154
  // Reopen sorts both hidden columns first, preserving table order.
145
155
  expect(getOptionTexts()).toEqual([
146
156
  "Show all",
157
+ "Hide all",
147
158
  "customer_name",
148
159
  "cust_age",
149
160
  "order_total",
@@ -189,6 +200,52 @@ describe("ColumnVisibilityDropdown", () => {
189
200
  );
190
201
  });
191
202
 
203
+ it("'Hide all' hides every hideable column", () => {
204
+ renderAndOpen();
205
+ fireEvent.click(getColumnOption("Hide all"));
206
+
207
+ expect(
208
+ getColumnOption("customer_name").querySelector(".lucide-eye-off"),
209
+ ).not.toBeNull();
210
+ expect(
211
+ getColumnOption("cust_age").querySelector(".lucide-eye-off"),
212
+ ).not.toBeNull();
213
+ expect(
214
+ getColumnOption("order_total").querySelector(".lucide-eye-off"),
215
+ ).not.toBeNull();
216
+ expect(getColumnOption("Hide all")).toHaveAttribute(
217
+ "aria-disabled",
218
+ "true",
219
+ );
220
+ });
221
+
222
+ it("disables 'Hide all' when every column is already hidden", () => {
223
+ renderAndOpen({
224
+ initiallyHidden: ["customer_name", "cust_age", "order_total"],
225
+ });
226
+ expect(getColumnOption("Hide all")).toHaveAttribute(
227
+ "aria-disabled",
228
+ "true",
229
+ );
230
+ });
231
+
232
+ it("'Hide all' leaves non-hideable columns visible", () => {
233
+ renderAndOpen({ nonHideable: ["customer_name"] });
234
+ fireEvent.click(getColumnOption("Hide all"));
235
+
236
+ expect(
237
+ getColumnOption("cust_age").querySelector(".lucide-eye-off"),
238
+ ).not.toBeNull();
239
+ const nonHideable = getColumnOption("customer_name");
240
+ expect(nonHideable).toHaveAttribute("aria-disabled", "true");
241
+ expect(nonHideable.querySelector(".lucide-eye-off")).toBeNull();
242
+ // Every hideable column is now hidden, so the action gates off.
243
+ expect(getColumnOption("Hide all")).toHaveAttribute(
244
+ "aria-disabled",
245
+ "true",
246
+ );
247
+ });
248
+
192
249
  it("hides and shows matching columns via bulk actions while searching", () => {
193
250
  renderAndOpen();
194
251
  fireEvent.change(getSearchInput(), { target: { value: "cust" } });