@marimo-team/islands 0.23.2-dev34 → 0.23.2-dev38

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
@@ -10510,7 +10510,7 @@ Defaulting to \`null\`.`;
10510
10510
  function set$1(e, r, c) {
10511
10511
  return e == null ? e : _baseSet_default(e, r, c);
10512
10512
  }
10513
- var set_default = set$1, import_compiler_runtime$142 = require_compiler_runtime(), hydratedMap = /* @__PURE__ */ new WeakMap();
10513
+ var set_default = set$1, import_compiler_runtime$143 = require_compiler_runtime(), hydratedMap = /* @__PURE__ */ new WeakMap();
10514
10514
  function useHydrateAtoms(e, r) {
10515
10515
  let c = useStore(r), d = getHydratedSet(c);
10516
10516
  for (let [f, ...h] of e) (!d.has(f) || (r == null ? void 0 : r.dangerouslyForceHydrate)) && (d.add(f), c.set(f, ...h));
@@ -13803,7 +13803,7 @@ Defaulting to \`null\`.`;
13803
13803
  }
13804
13804
  repl(MODEL_MANAGER, "MODEL_MANAGER");
13805
13805
  var NavigationMenu = import_react.forwardRef((e, r) => {
13806
- let c = (0, import_compiler_runtime$142.c)(16), d, f, h, _;
13806
+ let c = (0, import_compiler_runtime$143.c)(16), d, f, h, _;
13807
13807
  c[0] === e ? (d = c[1], f = c[2], h = c[3], _ = c[4]) : ({ className: f, children: d, orientation: h, ..._ } = e, c[0] = e, c[1] = d, c[2] = f, c[3] = h, c[4] = _);
13808
13808
  let y = h === "horizontal" && "max-w-max flex-1 items-center justify-center", S = h === "vertical" && "", w;
13809
13809
  c[5] !== f || c[6] !== y || c[7] !== S ? (w = cn(y, S, "relative z-10", f), c[5] = f, c[6] = y, c[7] = S, c[8] = w) : w = c[8];
@@ -13833,7 +13833,7 @@ Defaulting to \`null\`.`;
13833
13833
  orientation: "horizontal"
13834
13834
  }
13835
13835
  }), NavigationMenuList = import_react.forwardRef((e, r) => {
13836
- let c = (0, import_compiler_runtime$142.c)(11), d, f, h;
13836
+ let c = (0, import_compiler_runtime$143.c)(11), d, f, h;
13837
13837
  c[0] === e ? (d = c[1], f = c[2], h = c[3]) : ({ className: d, orientation: f, ...h } = e, c[0] = e, c[1] = d, c[2] = f, c[3] = h);
13838
13838
  let _;
13839
13839
  c[4] !== d || c[5] !== f ? (_ = cn(navigationMenuListStyle({
@@ -13858,7 +13858,7 @@ Defaulting to \`null\`.`;
13858
13858
  orientation: "horizontal"
13859
13859
  }
13860
13860
  }), NavigationMenuTrigger = import_react.forwardRef((e, r) => {
13861
- let c = (0, import_compiler_runtime$142.c)(12), d, f, h;
13861
+ let c = (0, import_compiler_runtime$143.c)(12), d, f, h;
13862
13862
  c[0] === e ? (d = c[1], f = c[2], h = c[3]) : ({ className: f, children: d, ...h } = e, c[0] = e, c[1] = d, c[2] = f, c[3] = h);
13863
13863
  let _;
13864
13864
  c[4] === f ? _ = c[5] : (_ = cn(navigationMenuTriggerStyle(), "group", f), c[4] = f, c[5] = _);
@@ -13881,7 +13881,7 @@ Defaulting to \`null\`.`;
13881
13881
  });
13882
13882
  NavigationMenuTrigger.displayName = Trigger$1.displayName;
13883
13883
  var NavigationMenuContent = import_react.forwardRef((e, r) => {
13884
- let c = (0, import_compiler_runtime$142.c)(9), d, f;
13884
+ let c = (0, import_compiler_runtime$143.c)(9), d, f;
13885
13885
  c[0] === e ? (d = c[1], f = c[2]) : ({ className: d, ...f } = e, c[0] = e, c[1] = d, c[2] = f);
13886
13886
  let h;
13887
13887
  c[3] === d ? h = c[4] : (h = cn("left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto ", d), c[3] = d, c[4] = h);
@@ -13894,7 +13894,7 @@ Defaulting to \`null\`.`;
13894
13894
  });
13895
13895
  NavigationMenuContent.displayName = Content$1.displayName;
13896
13896
  var NavigationMenuLink = Link, NavigationMenuViewport = import_react.forwardRef((e, r) => {
13897
- let c = (0, import_compiler_runtime$142.c)(10), d, f;
13897
+ let c = (0, import_compiler_runtime$143.c)(10), d, f;
13898
13898
  c[0] === e ? (d = c[1], f = c[2]) : ({ className: d, ...f } = e, c[0] = e, c[1] = d, c[2] = f);
13899
13899
  let h;
13900
13900
  c[3] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (h = cn("absolute left-0 top-full flex justify-center"), c[3] = h) : h = c[3];
@@ -13912,7 +13912,7 @@ Defaulting to \`null\`.`;
13912
13912
  });
13913
13913
  NavigationMenuViewport.displayName = Viewport.displayName;
13914
13914
  var NavigationMenuIndicator = import_react.forwardRef((e, r) => {
13915
- let c = (0, import_compiler_runtime$142.c)(10), d, f;
13915
+ let c = (0, import_compiler_runtime$143.c)(10), d, f;
13916
13916
  c[0] === e ? (d = c[1], f = c[2]) : ({ className: d, ...f } = e, c[0] = e, c[1] = d, c[2] = f);
13917
13917
  let h;
13918
13918
  c[3] === d ? h = c[4] : (h = cn("top-full z-1 flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in", d), c[3] = d, c[4] = h);
@@ -13929,7 +13929,7 @@ Defaulting to \`null\`.`;
13929
13929
  }), c[6] = f, c[7] = r, c[8] = h, c[9] = y) : y = c[9], y;
13930
13930
  });
13931
13931
  NavigationMenuIndicator.displayName = Indicator$2.displayName;
13932
- var import_compiler_runtime$141 = require_compiler_runtime(), NavigationMenuPlugin = class {
13932
+ var import_compiler_runtime$142 = require_compiler_runtime(), NavigationMenuPlugin = class {
13933
13933
  constructor() {
13934
13934
  __publicField(this, "tagName", "marimo-nav-menu");
13935
13935
  __publicField(this, "menuItemValidator", object({
@@ -13958,7 +13958,7 @@ Defaulting to \`null\`.`;
13958
13958
  });
13959
13959
  }
13960
13960
  }, NavMenuComponent = (e) => {
13961
- let r = (0, import_compiler_runtime$141.c)(13), { items: c, orientation: d } = e, f = _temp$38, h = _temp2$25, _ = _temp3$17, v;
13961
+ let r = (0, import_compiler_runtime$142.c)(13), { items: c, orientation: d } = e, f = _temp$38, h = _temp2$25, _ = _temp3$17, v;
13962
13962
  r[0] === d ? v = r[1] : (v = (e2) => "items" in e2 ? d === "horizontal" ? (0, import_jsx_runtime.jsx)(NavigationMenu, {
13963
13963
  orientation: "horizontal",
13964
13964
  children: (0, import_jsx_runtime.jsx)(NavigationMenuList, {
@@ -14039,7 +14039,7 @@ Defaulting to \`null\`.`;
14039
14039
  children: w
14040
14040
  }), r[10] = d, r[11] = w, r[12] = E) : E = r[12], E;
14041
14041
  }, ListItem = import_react.forwardRef((e, r) => {
14042
- let c = (0, import_compiler_runtime$141.c)(19), d, f, h, _;
14042
+ let c = (0, import_compiler_runtime$142.c)(19), d, f, h, _;
14043
14043
  c[0] === e ? (d = c[1], f = c[2], h = c[3], _ = c[4]) : ({ className: f, label: h, children: d, ..._ } = e, c[0] = e, c[1] = d, c[2] = f, c[3] = h, c[4] = _);
14044
14044
  let y;
14045
14045
  c[5] === f ? y = c[6] : (y = cn("block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-hidden transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground", f), c[5] = f, c[6] = y);
@@ -16939,9 +16939,9 @@ Defaulting to \`null\`.`;
16939
16939
  isSelected: _
16940
16940
  }
16941
16941
  }, M.children));
16942
- }), import_compiler_runtime$140 = require_compiler_runtime();
16942
+ }), import_compiler_runtime$141 = require_compiler_runtime();
16943
16943
  const LocaleProvider = (e) => {
16944
- let r = (0, import_compiler_runtime$140.c)(5), { children: c } = e, d = useAtomValue(localeAtom), f;
16944
+ let r = (0, import_compiler_runtime$141.c)(5), { children: c } = e, d = useAtomValue(localeAtom), f;
16945
16945
  r[0] === d ? f = r[1] : (f = safeLocale(d), r[0] = d, r[1] = f);
16946
16946
  let h;
16947
16947
  return r[2] !== c || r[3] !== f ? (h = (0, import_jsx_runtime.jsx)($18f2051aff69b9bf$export$a54013f0d02a8f82, {
@@ -17920,9 +17920,9 @@ Defaulting to \`null\`.`;
17920
17920
  r,
17921
17921
  d.name
17922
17922
  ]), null;
17923
- }), import_compiler_runtime$139 = require_compiler_runtime();
17923
+ }), import_compiler_runtime$140 = require_compiler_runtime();
17924
17924
  const EmotionCacheProvider = (e) => {
17925
- let r = (0, import_compiler_runtime$139.c)(6), { container: c, children: d } = e, f;
17925
+ let r = (0, import_compiler_runtime$140.c)(6), { container: c, children: d } = e, f;
17926
17926
  bb0: {
17927
17927
  if (!c) {
17928
17928
  let e3;
@@ -23090,9 +23090,9 @@ To suppress this warning, you need to explicitly provide the \`palette.${r}Chann
23090
23090
  })
23091
23091
  })
23092
23092
  });
23093
- }, import_compiler_runtime$138 = require_compiler_runtime();
23093
+ }, import_compiler_runtime$139 = require_compiler_runtime();
23094
23094
  const HtmlOutput = (0, import_react.memo)((e) => {
23095
- let r = (0, import_compiler_runtime$138.c)(10), { html: c, inline: d, className: f, alwaysSanitizeHtml: h } = e, _ = d === void 0 ? false : d;
23095
+ let r = (0, import_compiler_runtime$139.c)(10), { html: c, inline: d, className: f, alwaysSanitizeHtml: h } = e, _ = d === void 0 ? false : d;
23096
23096
  if (!c) return null;
23097
23097
  let y = !_, S;
23098
23098
  r[0] !== f || r[1] !== _ || r[2] !== y ? (S = cn(f, {
@@ -23111,9 +23111,9 @@ To suppress this warning, you need to explicitly provide the \`palette.${r}Chann
23111
23111
  }), r[7] = S, r[8] = w, r[9] = E) : E = r[9], E;
23112
23112
  });
23113
23113
  HtmlOutput.displayName = "HtmlOutput";
23114
- var import_compiler_runtime$137 = require_compiler_runtime();
23114
+ var import_compiler_runtime$138 = require_compiler_runtime();
23115
23115
  const ImageOutput = (e) => {
23116
- let r = (0, import_compiler_runtime$137.c)(8), { src: c, alt: d, width: f, height: h, className: _ } = e, v = d === void 0 ? "" : d, y;
23116
+ let r = (0, import_compiler_runtime$138.c)(8), { src: c, alt: d, width: f, height: h, className: _ } = e, v = d === void 0 ? "" : d, y;
23117
23117
  r[0] !== v || r[1] !== h || r[2] !== c || r[3] !== f ? (y = (0, import_jsx_runtime.jsx)("img", {
23118
23118
  src: c,
23119
23119
  alt: v,
@@ -23126,9 +23126,9 @@ To suppress this warning, you need to explicitly provide the \`palette.${r}Chann
23126
23126
  children: y
23127
23127
  }), r[5] = _, r[6] = y, r[7] = S) : S = r[7], S;
23128
23128
  };
23129
- var import_compiler_runtime$136 = require_compiler_runtime();
23129
+ var import_compiler_runtime$137 = require_compiler_runtime();
23130
23130
  const Kbd = (e) => {
23131
- let r = (0, import_compiler_runtime$136.c)(5), c;
23131
+ let r = (0, import_compiler_runtime$137.c)(5), c;
23132
23132
  r[0] === e.className ? c = r[1] : (c = clsx_default(e.className, "rounded-md bg-muted/40 px-2 text-[0.75rem] font-prose center border border-foreground/20 text-muted-foreground block whitespace-nowrap"), r[0] = e.className, r[1] = c);
23133
23133
  let d;
23134
23134
  return r[2] !== e.children || r[3] !== c ? (d = (0, import_jsx_runtime.jsx)("kbd", {
@@ -23136,9 +23136,9 @@ To suppress this warning, you need to explicitly provide the \`palette.${r}Chann
23136
23136
  children: e.children
23137
23137
  }), r[2] = e.children, r[3] = c, r[4] = d) : d = r[4], d;
23138
23138
  };
23139
- var import_compiler_runtime$135 = require_compiler_runtime();
23139
+ var import_compiler_runtime$136 = require_compiler_runtime();
23140
23140
  const ExternalLink$1 = (e) => {
23141
- let r = (0, import_compiler_runtime$135.c)(3), { href: c, children: d } = e, f;
23141
+ let r = (0, import_compiler_runtime$136.c)(3), { href: c, children: d } = e, f;
23142
23142
  return r[0] !== d || r[1] !== c ? (f = (0, import_jsx_runtime.jsx)("a", {
23143
23143
  href: c,
23144
23144
  target: "_blank",
@@ -23309,17 +23309,17 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
23309
23309
  os: "os",
23310
23310
  re: "re",
23311
23311
  sys: "sys"
23312
- }, import_compiler_runtime$134 = require_compiler_runtime(), fixModeAtom = atomWithStorage("marimo:ai-autofix-mode", "autofix", jotaiJsonStorage);
23312
+ }, import_compiler_runtime$135 = require_compiler_runtime(), fixModeAtom = atomWithStorage("marimo:ai-autofix-mode", "autofix", jotaiJsonStorage);
23313
23313
  function useFixMode() {
23314
- let e = (0, import_compiler_runtime$134.c)(3), [r, c] = useAtom(fixModeAtom), d;
23314
+ let e = (0, import_compiler_runtime$135.c)(3), [r, c] = useAtom(fixModeAtom), d;
23315
23315
  return e[0] !== r || e[1] !== c ? (d = {
23316
23316
  fixMode: r,
23317
23317
  setFixMode: c
23318
23318
  }, e[0] = r, e[1] = c, e[2] = d) : d = e[2], d;
23319
23319
  }
23320
- var import_compiler_runtime$133 = require_compiler_runtime();
23320
+ var import_compiler_runtime$134 = require_compiler_runtime();
23321
23321
  const AutoFixButton = (e) => {
23322
- let r = (0, import_compiler_runtime$133.c)(21), { errors: c, cellId: d, className: f } = e, h = useStore(), { createNewCell: _ } = useCellActions(), y = useAtomValue(aiEnabledAtom), S;
23322
+ let r = (0, import_compiler_runtime$134.c)(21), { errors: c, cellId: d, className: f } = e, h = useStore(), { createNewCell: _ } = useCellActions(), y = useAtomValue(aiEnabledAtom), S;
23323
23323
  if (r[0] !== y || r[1] !== c) {
23324
23324
  let e2;
23325
23325
  r[3] === y ? e2 = r[4] : (e2 = (e3) => getAutoFixes(e3, {
@@ -23380,7 +23380,7 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
23380
23380
  };
23381
23381
  var PromptIcon = Sparkles, AutofixIcon = Wrench, PromptTitle = "Suggest a prompt", AutofixTitle = "Fix with AI";
23382
23382
  const AIFixButton = (e) => {
23383
- let r = (0, import_compiler_runtime$133.c)(21), { tooltip: c, openPrompt: d, applyAutofix: f } = e, { fixMode: h, setFixMode: _ } = useFixMode(), v = h === "prompt" ? d : f, y;
23383
+ let r = (0, import_compiler_runtime$134.c)(21), { tooltip: c, openPrompt: d, applyAutofix: f } = e, { fixMode: h, setFixMode: _ } = useFixMode(), v = h === "prompt" ? d : f, y;
23384
23384
  r[0] === h ? y = r[1] : (y = h === "prompt" ? (0, import_jsx_runtime.jsx)(PromptIcon, {
23385
23385
  className: "h-3 w-3 mr-2 mb-0.5"
23386
23386
  }) : (0, import_jsx_runtime.jsx)(AutofixIcon, {
@@ -23449,7 +23449,7 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
23449
23449
  }), r[18] = G, r[19] = E, r[20] = q) : q = r[20], q;
23450
23450
  };
23451
23451
  var AiModeItem = (e) => {
23452
- let r = (0, import_compiler_runtime$133.c)(12), { mode: c } = e, d;
23452
+ let r = (0, import_compiler_runtime$134.c)(12), { mode: c } = e, d;
23453
23453
  r[0] === c ? d = r[1] : (d = c === "prompt" ? (0, import_jsx_runtime.jsx)(PromptIcon, {
23454
23454
  className: "h-4 w-4"
23455
23455
  }) : (0, import_jsx_runtime.jsx)(AutofixIcon, {
@@ -23486,9 +23486,9 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
23486
23486
  function useFilename() {
23487
23487
  return useAtomValue(filenameAtom);
23488
23488
  }
23489
- var import_compiler_runtime$131 = require_compiler_runtime();
23489
+ var import_compiler_runtime$132 = require_compiler_runtime();
23490
23490
  const CellLink = (e) => {
23491
- let r = (0, import_compiler_runtime$131.c)(12), { className: c, cellId: d, variant: f, onClick: h, formatCellName: _, skipScroll: y } = e, S = useCellNames()[d] ?? "", w = useCellIds().inOrderIds.indexOf(d), { showCellIfHidden: E } = useCellActions(), O = _ ?? _temp$37, M;
23491
+ let r = (0, import_compiler_runtime$132.c)(12), { className: c, cellId: d, variant: f, onClick: h, formatCellName: _, skipScroll: y } = e, S = useCellNames()[d] ?? "", w = useCellIds().inOrderIds.indexOf(d), { showCellIfHidden: E } = useCellActions(), O = _ ?? _temp$37, M;
23492
23492
  r[0] === c ? M = r[1] : (M = cn("inline-block cursor-pointer text-link hover:underline", c), r[0] = c, r[1] = M);
23493
23493
  let I;
23494
23494
  r[2] !== d || r[3] !== h || r[4] !== E || r[5] !== y || r[6] !== f ? (I = (e2) => {
@@ -23508,13 +23508,13 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
23508
23508
  children: z
23509
23509
  }), r[8] = M, r[9] = I, r[10] = z, r[11] = Y7) : Y7 = r[11], Y7;
23510
23510
  }, CellLinkError = (e) => {
23511
- let r = (0, import_compiler_runtime$131.c)(2), c;
23511
+ let r = (0, import_compiler_runtime$132.c)(2), c;
23512
23512
  return r[0] === e ? c = r[1] : (c = (0, import_jsx_runtime.jsx)(CellLink, {
23513
23513
  ...e,
23514
23514
  variant: "destructive"
23515
23515
  }), r[0] = e, r[1] = c), c;
23516
23516
  }, CellLinkTraceback = (e) => {
23517
- let r = (0, import_compiler_runtime$131.c)(10), { cellId: c, lineNumber: d } = e, f = useFilename(), h;
23517
+ let r = (0, import_compiler_runtime$132.c)(10), { cellId: c, lineNumber: d } = e, f = useFilename(), h;
23518
23518
  r[0] !== c || r[1] !== d ? (h = () => goToCellLine(c, d), r[0] = c, r[1] = d, r[2] = h) : h = r[2];
23519
23519
  let _;
23520
23520
  r[3] !== c || r[4] !== f ? (_ = (e2) => c === "__scratch__" ? "scratch" : `marimo://${f || "untitled"}#cell=${e2}`, r[3] = c, r[4] = f, r[5] = _) : _ = r[5];
@@ -23611,7 +23611,7 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
23611
23611
  value: e2
23612
23612
  });
23613
23613
  }
23614
- var import_compiler_runtime$130 = require_compiler_runtime(), ansiUp = new AnsiUp();
23614
+ var import_compiler_runtime$131 = require_compiler_runtime(), ansiUp = new AnsiUp();
23615
23615
  const cleanAnsiCodes = (e) => {
23616
23616
  let r = RegExp("\x1B\\[[0-9;]*m", "g");
23617
23617
  return e.replaceAll(r, "");
@@ -23679,7 +23679,7 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
23679
23679
  });
23680
23680
  }
23681
23681
  var InstallPackageLink = (e) => {
23682
- let r = (0, import_compiler_runtime$130.c)(6), { packages: c, children: d } = e, { handleInstallPackages: f } = useInstallPackages(), h;
23682
+ let r = (0, import_compiler_runtime$131.c)(6), { packages: c, children: d } = e, { handleInstallPackages: f } = useInstallPackages(), h;
23683
23683
  r[0] !== f || r[1] !== c ? (h = (e2) => {
23684
23684
  f(c), e2.preventDefault();
23685
23685
  }, r[0] = f, r[1] = c, r[2] = h) : h = r[2];
@@ -23747,15 +23747,15 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
23747
23747
  replace: (e2) => r(e2)
23748
23748
  })
23749
23749
  }), RenderTextWithLinks = (e) => {
23750
- let r = (0, import_compiler_runtime$130.c)(4), { text: c } = e, d;
23750
+ let r = (0, import_compiler_runtime$131.c)(4), { text: c } = e, d;
23751
23751
  r[0] === c ? d = r[1] : (d = renderTextWithReplacers(c, composeReplacers(pipInstallReplacer, urlReplacer)), r[0] = c, r[1] = d);
23752
23752
  let f = d, h;
23753
23753
  return r[2] === f ? h = r[3] : (h = (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, {
23754
23754
  children: f
23755
23755
  }), r[2] = f, r[3] = h), h;
23756
23756
  };
23757
- var import_compiler_runtime$129 = require_compiler_runtime(), Tip = (e) => {
23758
- let r = (0, import_compiler_runtime$129.c)(10), c = e.title ?? "Tip", d;
23757
+ var import_compiler_runtime$130 = require_compiler_runtime(), Tip = (e) => {
23758
+ let r = (0, import_compiler_runtime$130.c)(10), c = e.title ?? "Tip", d;
23759
23759
  r[0] === c ? d = r[1] : (d = (0, import_jsx_runtime.jsx)(AccordionTrigger, {
23760
23760
  className: "pt-2 pb-2 font-normal",
23761
23761
  children: c
@@ -23783,7 +23783,7 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
23783
23783
  }), r[7] = e.className, r[8] = h, r[9] = _) : _ = r[9], _;
23784
23784
  };
23785
23785
  const MarimoErrorOutput = (e) => {
23786
- let r = (0, import_compiler_runtime$129.c)(31), { errors: c, cellId: d, className: f } = e, h = useChromeActions(), _ = "This cell wasn't run because it has errors", y = "destructive", S = "text-error";
23786
+ let r = (0, import_compiler_runtime$130.c)(31), { errors: c, cellId: d, className: f } = e, h = useChromeActions(), _ = "This cell wasn't run because it has errors", y = "destructive", S = "text-error";
23787
23787
  if (c.some(_temp$36)) _ = "Interrupted";
23788
23788
  else if (c.some(_temp2$24)) _ = "An internal error occurred";
23789
23789
  else if (c.some(_temp3$16)) _ = "Ancestor prevented from running", y = "default", S = "text-secondary-foreground";
@@ -24460,9 +24460,9 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
24460
24460
  })
24461
24461
  }, `sql-error-${r}`);
24462
24462
  }
24463
- var import_compiler_runtime$128 = require_compiler_runtime();
24463
+ var import_compiler_runtime$129 = require_compiler_runtime();
24464
24464
  const TextOutput = (e) => {
24465
- let r = (0, import_compiler_runtime$128.c)(13), { text: c, channel: d, wrapText: f } = e, h = d === "stdout" || d === "stderr", _;
24465
+ let r = (0, import_compiler_runtime$129.c)(13), { text: c, channel: d, wrapText: f } = e, h = d === "stdout" || d === "stderr", _;
24466
24466
  r[0] === f ? _ = r[1] : (_ = (e2) => (0, import_jsx_runtime.jsx)("span", {
24467
24467
  className: f ? "whitespace-pre-wrap break-words" : "whitespace-pre",
24468
24468
  children: (0, import_jsx_runtime.jsx)(RenderTextWithLinks, {
@@ -24479,17 +24479,17 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
24479
24479
  children: O
24480
24480
  }), r[10] = E, r[11] = O, r[12] = M) : M = r[12], M;
24481
24481
  };
24482
- var import_compiler_runtime$127 = require_compiler_runtime();
24482
+ var import_compiler_runtime$128 = require_compiler_runtime();
24483
24483
  const VideoOutput = (e) => {
24484
- let r = (0, import_compiler_runtime$127.c)(3), { src: c, className: d } = e, f;
24484
+ let r = (0, import_compiler_runtime$128.c)(3), { src: c, className: d } = e, f;
24485
24485
  return r[0] !== d || r[1] !== c ? (f = (0, import_jsx_runtime.jsx)("iframe", {
24486
24486
  className: d,
24487
24487
  src: c
24488
24488
  }), r[0] = d, r[1] = c, r[2] = f) : f = r[2], f;
24489
24489
  };
24490
- var import_compiler_runtime$126 = require_compiler_runtime();
24490
+ var import_compiler_runtime$127 = require_compiler_runtime();
24491
24491
  function useOverflowDetection(e, r) {
24492
- let c = (0, import_compiler_runtime$126.c)(4), d = r === void 0 ? true : r, [f, h] = (0, import_react.useState)(false), _, v;
24492
+ let c = (0, import_compiler_runtime$127.c)(4), d = r === void 0 ? true : r, [f, h] = (0, import_react.useState)(false), _, v;
24493
24493
  return c[0] !== d || c[1] !== e ? (_ = () => {
24494
24494
  let r2 = e.current;
24495
24495
  if (!r2 || !d) return;
@@ -24586,9 +24586,9 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
24586
24586
  const LazyVegaEmbed = import_react.lazy(() => import("./react-vega-BFLRzgl7.js").then((e) => ({
24587
24587
  default: e.VegaEmbed
24588
24588
  })));
24589
- var import_compiler_runtime$125 = require_compiler_runtime();
24589
+ var import_compiler_runtime$126 = require_compiler_runtime();
24590
24590
  const ChartLoadingState = () => {
24591
- let e = (0, import_compiler_runtime$125.c)(1), r;
24591
+ let e = (0, import_compiler_runtime$126.c)(1), r;
24592
24592
  return e[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (r = (0, import_jsx_runtime.jsxs)("div", {
24593
24593
  className: "flex items-center gap-2 justify-center",
24594
24594
  children: [
@@ -24602,7 +24602,7 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
24602
24602
  ]
24603
24603
  }), e[0] = r) : r = e[0], r;
24604
24604
  }, ChartErrorState = (e) => {
24605
- let r = (0, import_compiler_runtime$125.c)(2), { error: c } = e, d;
24605
+ let r = (0, import_compiler_runtime$126.c)(2), { error: c } = e, d;
24606
24606
  return r[0] === c ? d = r[1] : (d = (0, import_jsx_runtime.jsx)("div", {
24607
24607
  className: "flex items-center justify-center",
24608
24608
  children: (0, import_jsx_runtime.jsx)(ErrorBanner, {
@@ -24610,7 +24610,7 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
24610
24610
  })
24611
24611
  }), r[0] = c, r[1] = d), d;
24612
24612
  }, ChartInfoState = (e) => {
24613
- let r = (0, import_compiler_runtime$125.c)(8), { children: c, className: d } = e, f;
24613
+ let r = (0, import_compiler_runtime$126.c)(8), { children: c, className: d } = e, f;
24614
24614
  r[0] === d ? f = r[1] : (f = cn("flex flex-col items-center justify-center gap-4", d), r[0] = d, r[1] = f);
24615
24615
  let h;
24616
24616
  r[2] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (h = (0, import_jsx_runtime.jsx)(ChartPie, {
@@ -24630,8 +24630,8 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
24630
24630
  ]
24631
24631
  }), r[5] = f, r[6] = _, r[7] = y) : y = r[7], y;
24632
24632
  };
24633
- var import_compiler_runtime$124 = require_compiler_runtime(), Tabs = Root2, TabsList = import_react.forwardRef((e, r) => {
24634
- let c = (0, import_compiler_runtime$124.c)(9), d, f;
24633
+ var import_compiler_runtime$125 = require_compiler_runtime(), Tabs = Root2, TabsList = import_react.forwardRef((e, r) => {
24634
+ let c = (0, import_compiler_runtime$125.c)(9), d, f;
24635
24635
  c[0] === e ? (d = c[1], f = c[2]) : ({ className: d, ...f } = e, c[0] = e, c[1] = d, c[2] = f);
24636
24636
  let h;
24637
24637
  c[3] === d ? h = c[4] : (h = cn("inline-flex max-h-14 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground", d), c[3] = d, c[4] = h);
@@ -24644,7 +24644,7 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
24644
24644
  });
24645
24645
  TabsList.displayName = List.displayName;
24646
24646
  var TabsTrigger = import_react.forwardRef((e, r) => {
24647
- let c = (0, import_compiler_runtime$124.c)(9), d, f;
24647
+ let c = (0, import_compiler_runtime$125.c)(9), d, f;
24648
24648
  c[0] === e ? (d = c[1], f = c[2]) : ({ className: d, ...f } = e, c[0] = e, c[1] = d, c[2] = f);
24649
24649
  let h;
24650
24650
  c[3] === d ? h = c[4] : (h = cn("inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm", d), c[3] = d, c[4] = h);
@@ -24657,7 +24657,7 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
24657
24657
  });
24658
24658
  TabsTrigger.displayName = Trigger.displayName;
24659
24659
  var TabsContent = import_react.forwardRef((e, r) => {
24660
- let c = (0, import_compiler_runtime$124.c)(9), d, f;
24660
+ let c = (0, import_compiler_runtime$125.c)(9), d, f;
24661
24661
  c[0] === e ? (d = c[1], f = c[2]) : ({ className: d, ...f } = e, c[0] = e, c[1] = d, c[2] = f);
24662
24662
  let h;
24663
24663
  c[3] === d ? h = c[4] : (h = cn("mt-2 ring-offset-background focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2", d), c[3] = d, c[4] = h);
@@ -24669,9 +24669,9 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
24669
24669
  }), c[5] = f, c[6] = r, c[7] = h, c[8] = _) : _ = c[8], _;
24670
24670
  });
24671
24671
  TabsContent.displayName = Content.displayName;
24672
- var import_compiler_runtime$123 = require_compiler_runtime();
24672
+ var import_compiler_runtime$124 = require_compiler_runtime();
24673
24673
  const WithLocale = (e) => {
24674
- let r = (0, import_compiler_runtime$123.c)(3), { children: c } = e, { locale: d } = $18f2051aff69b9bf$export$43bb16f9c6d9e3f7(), f;
24674
+ let r = (0, import_compiler_runtime$124.c)(3), { children: c } = e, { locale: d } = $18f2051aff69b9bf$export$43bb16f9c6d9e3f7(), f;
24675
24675
  return r[0] !== c || r[1] !== d ? (f = c(d), r[0] = c, r[1] = d, r[2] = f) : f = r[2], f;
24676
24676
  };
24677
24677
  function tzName(e, r, c = "long") {
@@ -25490,8 +25490,8 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
25490
25490
  function smartMatchFilter(e, r, c) {
25491
25491
  return smartMatch(r, e) ? 1 : c && smartMatch(r, c) ? 0.8 : 0;
25492
25492
  }
25493
- var import_compiler_runtime$122 = require_compiler_runtime(), Command = import_react.forwardRef((e, r) => {
25494
- let c = (0, import_compiler_runtime$122.c)(9), d, f;
25493
+ var import_compiler_runtime$123 = require_compiler_runtime(), Command = import_react.forwardRef((e, r) => {
25494
+ let c = (0, import_compiler_runtime$123.c)(9), d, f;
25495
25495
  c[0] === e ? (d = c[1], f = c[2]) : ({ className: d, ...f } = e, c[0] = e, c[1] = d, c[2] = f);
25496
25496
  let h;
25497
25497
  c[3] === d ? h = c[4] : (h = cn("flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground", d), c[3] = d, c[4] = h);
@@ -25505,7 +25505,7 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
25505
25505
  });
25506
25506
  Command.displayName = _e$1.displayName;
25507
25507
  var CommandInput = import_react.forwardRef((e, r) => {
25508
- let c = (0, import_compiler_runtime$122.c)(19), d, f, h, _;
25508
+ let c = (0, import_compiler_runtime$123.c)(19), d, f, h, _;
25509
25509
  c[0] === e ? (d = c[1], f = c[2], h = c[3], _ = c[4]) : ({ className: d, icon: f, rootClassName: _, ...h } = e, c[0] = e, c[1] = d, c[2] = f, c[3] = h, c[4] = _);
25510
25510
  let y;
25511
25511
  c[5] === _ ? y = c[6] : (y = cn("flex items-center border-b px-3", _), c[5] = _, c[6] = y);
@@ -25533,7 +25533,7 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
25533
25533
  });
25534
25534
  CommandInput.displayName = _e$1.Input.displayName;
25535
25535
  var CommandList = import_react.forwardRef((e, r) => {
25536
- let c = (0, import_compiler_runtime$122.c)(9), d, f;
25536
+ let c = (0, import_compiler_runtime$123.c)(9), d, f;
25537
25537
  c[0] === e ? (d = c[1], f = c[2]) : ({ className: d, ...f } = e, c[0] = e, c[1] = d, c[2] = f);
25538
25538
  let h;
25539
25539
  c[3] === d ? h = c[4] : (h = cn("max-h-[300px] overflow-y-auto overflow-x-hidden", d), c[3] = d, c[4] = h);
@@ -25546,7 +25546,7 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
25546
25546
  });
25547
25547
  CommandList.displayName = _e$1.List.displayName;
25548
25548
  var CommandEmpty = import_react.forwardRef((e, r) => {
25549
- let c = (0, import_compiler_runtime$122.c)(3), d;
25549
+ let c = (0, import_compiler_runtime$123.c)(3), d;
25550
25550
  return c[0] !== e || c[1] !== r ? (d = (0, import_jsx_runtime.jsx)(_e$1.Empty, {
25551
25551
  ref: r,
25552
25552
  className: "py-6 text-center text-sm",
@@ -25555,7 +25555,7 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
25555
25555
  });
25556
25556
  CommandEmpty.displayName = _e$1.Empty.displayName;
25557
25557
  var CommandGroup = import_react.forwardRef((e, r) => {
25558
- let c = (0, import_compiler_runtime$122.c)(9), d, f;
25558
+ let c = (0, import_compiler_runtime$123.c)(9), d, f;
25559
25559
  c[0] === e ? (d = c[1], f = c[2]) : ({ className: d, ...f } = e, c[0] = e, c[1] = d, c[2] = f);
25560
25560
  let h;
25561
25561
  c[3] === d ? h = c[4] : (h = cn("overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground", d), c[3] = d, c[4] = h);
@@ -25568,7 +25568,7 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
25568
25568
  });
25569
25569
  CommandGroup.displayName = _e$1.Group.displayName;
25570
25570
  var CommandSeparator = import_react.forwardRef((e, r) => {
25571
- let c = (0, import_compiler_runtime$122.c)(9), d, f;
25571
+ let c = (0, import_compiler_runtime$123.c)(9), d, f;
25572
25572
  c[0] === e ? (d = c[1], f = c[2]) : ({ className: d, ...f } = e, c[0] = e, c[1] = d, c[2] = f);
25573
25573
  let h;
25574
25574
  c[3] === d ? h = c[4] : (h = menuSeparatorVariants({
@@ -25583,7 +25583,7 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
25583
25583
  });
25584
25584
  CommandSeparator.displayName = _e$1.Separator.displayName;
25585
25585
  var CommandItem = import_react.forwardRef((e, r) => {
25586
- let c = (0, import_compiler_runtime$122.c)(17), d, f, h, _, y;
25586
+ let c = (0, import_compiler_runtime$123.c)(17), d, f, h, _, y;
25587
25587
  if (c[0] !== r || c[1] !== e) {
25588
25588
  let { className: S2, variant: w, inset: E, ...O } = e;
25589
25589
  d = _e$1.Item, f = r, c[7] !== S2 || c[8] !== E || c[9] !== w ? (h = cn(menuItemVariants({
@@ -25600,9 +25600,9 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
25600
25600
  }), c[11] = d, c[12] = f, c[13] = h, c[14] = _, c[15] = y, c[16] = S) : S = c[16], S;
25601
25601
  });
25602
25602
  CommandItem.displayName = _e$1.Item.displayName;
25603
- var import_compiler_runtime$121 = require_compiler_runtime();
25603
+ var import_compiler_runtime$122 = require_compiler_runtime();
25604
25604
  const DraggablePopover = (e) => {
25605
- let r = (0, import_compiler_runtime$121.c)(25), c, d, f;
25605
+ let r = (0, import_compiler_runtime$122.c)(25), c, d, f;
25606
25606
  r[0] === e ? (c = r[1], d = r[2], f = r[3]) : ({ children: c, className: d, ...f } = e, r[0] = e, r[1] = c, r[2] = d, r[3] = f);
25607
25607
  let h;
25608
25608
  r[4] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (h = {
@@ -25842,6 +25842,98 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
25842
25842
  negate: false
25843
25843
  };
25844
25844
  }
25845
+ var import_compiler_runtime$121 = require_compiler_runtime(), WHITESPACE_CHARS = {
25846
+ " ": {
25847
+ marker: "\u2423",
25848
+ name: "space"
25849
+ },
25850
+ " ": {
25851
+ marker: "\\t",
25852
+ name: "tab"
25853
+ },
25854
+ "\n": {
25855
+ marker: "\\n",
25856
+ name: "newline"
25857
+ },
25858
+ "\r": {
25859
+ marker: "\\r",
25860
+ name: "newline"
25861
+ }
25862
+ };
25863
+ function renderWhitespaceMarkers(e) {
25864
+ return [
25865
+ ...e
25866
+ ].map((e2) => {
25867
+ var _a3;
25868
+ return ((_a3 = WHITESPACE_CHARS[e2]) == null ? void 0 : _a3.marker) ?? e2;
25869
+ }).join("");
25870
+ }
25871
+ function describeWhitespace(e) {
25872
+ var _a3;
25873
+ let r = {};
25874
+ for (let c of e) {
25875
+ let e2 = ((_a3 = WHITESPACE_CHARS[c]) == null ? void 0 : _a3.name) ?? "character";
25876
+ r[e2] = (r[e2] ?? 0) + 1;
25877
+ }
25878
+ return Object.entries(r).map(([e2, r2]) => `${r2} ${e2}${r2 > 1 ? "s" : ""}`).join(", ");
25879
+ }
25880
+ var SENTINEL_CONFIG = {
25881
+ null: {
25882
+ label: () => "None",
25883
+ tooltip: () => "None",
25884
+ ariaLabel: () => "None"
25885
+ },
25886
+ "empty-string": {
25887
+ label: () => "<empty>",
25888
+ tooltip: () => "<empty>",
25889
+ ariaLabel: () => "empty string"
25890
+ },
25891
+ whitespace: {
25892
+ label: (e) => renderWhitespaceMarkers(String(e)),
25893
+ tooltip: (e) => describeWhitespace(String(e)),
25894
+ ariaLabel: (e) => describeWhitespace(String(e))
25895
+ },
25896
+ nan: {
25897
+ label: () => "NaN",
25898
+ tooltip: () => "NaN",
25899
+ ariaLabel: () => "NaN"
25900
+ },
25901
+ "positive-infinity": {
25902
+ label: () => "inf",
25903
+ tooltip: () => "Infinity",
25904
+ ariaLabel: () => "infinity"
25905
+ },
25906
+ "negative-infinity": {
25907
+ label: () => "-inf",
25908
+ tooltip: () => "-Infinity",
25909
+ ariaLabel: () => "negative infinity"
25910
+ },
25911
+ nat: {
25912
+ label: () => "NaT",
25913
+ tooltip: () => "NaT (Not a Time)",
25914
+ ariaLabel: () => "Not a Time"
25915
+ }
25916
+ };
25917
+ function SentinelCell(e) {
25918
+ let r = (0, import_compiler_runtime$121.c)(15), { sentinel: c } = e, d = SENTINEL_CONFIG[c.type], f;
25919
+ r[0] !== d || r[1] !== c.value ? (f = d.label(c.value), r[0] = d, r[1] = c.value, r[2] = f) : f = r[2];
25920
+ let h = f, _;
25921
+ r[3] !== d || r[4] !== c.value ? (_ = d.tooltip(c.value), r[3] = d, r[4] = c.value, r[5] = _) : _ = r[5];
25922
+ let v = _, y;
25923
+ r[6] !== d || r[7] !== c.value ? (y = d.ariaLabel(c.value), r[6] = d, r[7] = c.value, r[8] = y) : y = r[8];
25924
+ let S = y, w;
25925
+ r[9] === h ? w = r[10] : (w = (0, import_jsx_runtime.jsx)("span", {
25926
+ className: "opacity-70",
25927
+ children: h
25928
+ }), r[9] = h, r[10] = w);
25929
+ let E;
25930
+ return r[11] !== S || r[12] !== w || r[13] !== v ? (E = (0, import_jsx_runtime.jsx)("span", {
25931
+ className: "italic text-muted-foreground bg-muted rounded px-1",
25932
+ "aria-label": S,
25933
+ title: v,
25934
+ children: w
25935
+ }), r[11] = S, r[12] = w, r[13] = v, r[14] = E) : E = r[14], E;
25936
+ }
25845
25937
  function functionalUpdate(e, r) {
25846
25938
  return typeof e == "function" ? e(r) : e;
25847
25939
  }
@@ -28179,10 +28271,17 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
28179
28271
  return Objects.collect(e, ([e2]) => e2, ([, [e2]]) => e2);
28180
28272
  }
28181
28273
  const INDEX_COLUMN_NAME = "_marimo_row_id", TOO_MANY_ROWS = "too_many";
28274
+ function isNumericType(e) {
28275
+ return e === "number" || e === "integer";
28276
+ }
28277
+ function isTemporalType(e) {
28278
+ return e === "date" || e === "datetime" || e === "time";
28279
+ }
28182
28280
  function extractTimezone(e) {
28183
28281
  var _a3, _b3;
28184
28282
  if (e) return (_b3 = (_a3 = /^datetime(?:64)?\[[^,]+,([^,]+)]$/.exec(e)) == null ? void 0 : _a3[1]) == null ? void 0 : _b3.trim();
28185
28283
  }
28284
+ var WHITESPACE_ONLY_RE = /^[\s]+$/;
28186
28285
  async function loadTableData(e) {
28187
28286
  return Array.isArray(e) ? e : e.startsWith("{") || e.startsWith("[") ? jsonParseWithSpecialChar(e) : (e = await vegaLoadData(e, {
28188
28287
  type: "json"
@@ -28206,6 +28305,50 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
28206
28305
  let d = r * c, f = d + c - 1;
28207
28306
  return e < d || e > f ? Math.floor(e / c) : null;
28208
28307
  }
28308
+ var NUMERIC_STRING_SPECIALS = {
28309
+ NaN: "nan",
28310
+ Infinity: "positive-infinity",
28311
+ "-Infinity": "negative-infinity",
28312
+ inf: "positive-infinity",
28313
+ "-inf": "negative-infinity"
28314
+ };
28315
+ function detectSentinel(e, r) {
28316
+ if (e == null) return {
28317
+ type: "null",
28318
+ value: e
28319
+ };
28320
+ if (typeof e == "string") {
28321
+ if (e === "") return {
28322
+ type: "empty-string",
28323
+ value: e
28324
+ };
28325
+ if (WHITESPACE_ONLY_RE.test(e)) return {
28326
+ type: "whitespace",
28327
+ value: e
28328
+ };
28329
+ if (isNumericType(r)) {
28330
+ let r2 = NUMERIC_STRING_SPECIALS[e];
28331
+ if (r2) return {
28332
+ type: r2,
28333
+ value: e
28334
+ };
28335
+ }
28336
+ return isTemporalType(r) && e === "NaT" ? {
28337
+ type: "nat",
28338
+ value: e
28339
+ } : null;
28340
+ }
28341
+ return typeof e == "number" ? Number.isNaN(e) ? {
28342
+ type: "nan",
28343
+ value: e
28344
+ } : e === Infinity ? {
28345
+ type: "positive-infinity",
28346
+ value: e
28347
+ } : e === -Infinity ? {
28348
+ type: "negative-infinity",
28349
+ value: e
28350
+ } : null : null;
28351
+ }
28209
28352
  function stringifyUnknownValue(e) {
28210
28353
  let { value: r, nullAsEmptyString: c = false } = e;
28211
28354
  return typeof r == "object" && r ? JSON.stringify(r) : r === null && c ? "" : String(r);
@@ -28645,30 +28788,33 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
28645
28788
  })
28646
28789
  ]
28647
28790
  }),
28648
- E.map(([e3, r2], c2) => {
28649
- let f2 = d.has(e3), h = stringifyUnknownValue({
28791
+ E.map(([e3, r2], f2) => {
28792
+ var _a3;
28793
+ let h = d.has(e3), _2 = stringifyUnknownValue({
28650
28794
  value: e3
28651
- });
28795
+ }), v2 = detectSentinel(e3, (_a3 = c.columnDef.meta) == null ? void 0 : _a3.dataType);
28652
28796
  return (0, import_jsx_runtime.jsxs)(CommandItem, {
28653
- value: h,
28797
+ value: _2,
28654
28798
  className: "not-last:border-b rounded-none px-3",
28655
28799
  onSelect: () => M(e3),
28656
28800
  children: [
28657
28801
  (0, import_jsx_runtime.jsx)(Checkbox, {
28658
- checked: f2,
28802
+ checked: h,
28659
28803
  "aria-label": "Select row",
28660
28804
  className: "mr-3 h-3.5 w-3.5"
28661
28805
  }),
28662
28806
  (0, import_jsx_runtime.jsx)("span", {
28663
28807
  className: "flex-1 overflow-hidden max-h-20 line-clamp-3",
28664
- children: h
28808
+ children: v2 ? (0, import_jsx_runtime.jsx)(SentinelCell, {
28809
+ sentinel: v2
28810
+ }) : _2
28665
28811
  }),
28666
28812
  (0, import_jsx_runtime.jsx)("span", {
28667
28813
  className: "ml-3",
28668
28814
  children: r2
28669
28815
  })
28670
28816
  ]
28671
- }, c2);
28817
+ }, f2);
28672
28818
  })
28673
28819
  ]
28674
28820
  }),
@@ -30361,7 +30507,7 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
30361
30507
  }, I = (e2) => {
30362
30508
  if (f == null ? void 0 : f[e2]) return f[e2];
30363
30509
  let r2 = M(e2).dataType;
30364
- if (r2 === "number" || r2 === "integer") return "right";
30510
+ if (isNumericType(r2)) return "right";
30365
30511
  }, z = [
30366
30512
  ...E,
30367
30513
  ...c.map(([e2]) => e2)
@@ -30428,7 +30574,7 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
30428
30574
  wrapped: S2,
30429
30575
  canSelectCell: O2,
30430
30576
  isSelected: w2,
30431
- isNumeric: M2 === "number" || M2 === "integer"
30577
+ isNumeric: isNumericType(M2)
30432
30578
  })
30433
30579
  });
30434
30580
  return E.has(e2) ? (0, import_jsx_runtime.jsx)("b", {
@@ -30551,7 +30697,14 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
30551
30697
  }
30552
30698
  function renderCellValue({ column: e, renderValue: r, getValue: c, selectCell: d, cellStyles: f }) {
30553
30699
  var _a3, _b3, _c3, _d3, _e9;
30554
- let _ = c(), y = (_a3 = e.getColumnFormatting) == null ? void 0 : _a3.call(e), S = (_b3 = e.columnDef.meta) == null ? void 0 : _b3.dataType, w = (_c3 = e.columnDef.meta) == null ? void 0 : _c3.dtype, E = ((_d3 = e.getColumnWrapping) == null ? void 0 : _d3.call(e)) === "wrap";
30700
+ let _ = c(), y = (_a3 = e.getColumnFormatting) == null ? void 0 : _a3.call(e), S = (_b3 = e.columnDef.meta) == null ? void 0 : _b3.dataType, w = (_c3 = e.columnDef.meta) == null ? void 0 : _c3.dtype, E = ((_d3 = e.getColumnWrapping) == null ? void 0 : _d3.call(e)) === "wrap", O = detectSentinel(_, S);
30701
+ if (O && O.type !== "empty-string") return (0, import_jsx_runtime.jsx)("div", {
30702
+ onClick: d,
30703
+ className: f,
30704
+ children: (0, import_jsx_runtime.jsx)(SentinelCell, {
30705
+ sentinel: O
30706
+ })
30707
+ });
30555
30708
  if (S === "datetime" && typeof _ == "string") try {
30556
30709
  if (!isValid(_)) return (0, import_jsx_runtime.jsx)("div", {
30557
30710
  onClick: d,
@@ -30630,11 +30783,11 @@ Database schema: ${c}`), (_a4 = r2.aiFix) == null ? void 0 : _a4.setAiCompletion
30630
30783
  children: e2 == null ? "" : String(e2)
30631
30784
  });
30632
30785
  }
30633
- let O = getMimeValues(_);
30634
- return O ? (0, import_jsx_runtime.jsx)("div", {
30786
+ let M = getMimeValues(_);
30787
+ return M ? (0, import_jsx_runtime.jsx)("div", {
30635
30788
  onClick: d,
30636
30789
  className: f,
30637
- children: O.map((e2, r2) => (0, import_jsx_runtime.jsx)(MimeCell, {
30790
+ children: M.map((e2, r2) => (0, import_jsx_runtime.jsx)(MimeCell, {
30638
30791
  value: e2
30639
30792
  }, r2))
30640
30793
  }) : Array.isArray(_) || typeof _ == "object" ? (0, import_jsx_runtime.jsx)(PopoutColumn, {
@@ -68865,7 +69018,7 @@ ${c}
68865
69018
  return Logger.warn("Failed to get version from mount config"), null;
68866
69019
  }
68867
69020
  }
68868
- const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.23.2-dev34"), showCodeInRunModeAtom = atom(true);
69021
+ const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.23.2-dev38"), showCodeInRunModeAtom = atom(true);
68869
69022
  atom(null);
68870
69023
  var VIRTUAL_FILE_REGEX = /\/@file\/([^\s"&'/]+)\.([\dA-Za-z]+)/g, VirtualFileTracker = class e {
68871
69024
  constructor() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.23.2-dev34",
3
+ "version": "0.23.2-dev38",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -0,0 +1,83 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { render } from "@testing-library/react";
4
+ import { describe, expect, it } from "vitest";
5
+ import { SentinelCell } from "../sentinel-cell";
6
+ import type { CellValueSentinel } from "../types";
7
+
8
+ function renderSentinel(sentinel: CellValueSentinel) {
9
+ const { container } = render(<SentinelCell sentinel={sentinel} />);
10
+ return container.querySelector("span")!;
11
+ }
12
+
13
+ describe("SentinelCell", () => {
14
+ it("renders null as None", () => {
15
+ const span = renderSentinel({ type: "null", value: null });
16
+ expect(span.textContent).toBe("None");
17
+ expect(span.getAttribute("aria-label")).toBe("None");
18
+ expect(span.className).toContain("italic");
19
+ expect(span.className).toContain("bg-muted");
20
+ });
21
+
22
+ it("renders empty string as <empty>", () => {
23
+ const span = renderSentinel({ type: "empty-string", value: "" });
24
+ expect(span.textContent).toBe("<empty>");
25
+ expect(span.getAttribute("aria-label")).toBe("empty string");
26
+ });
27
+
28
+ it("renders single space", () => {
29
+ const span = renderSentinel({ type: "whitespace", value: " " });
30
+ expect(span.textContent).toBe("\u2423");
31
+ expect(span.getAttribute("aria-label")).toBe("1 space");
32
+ });
33
+
34
+ it("renders multiple spaces", () => {
35
+ const span = renderSentinel({ type: "whitespace", value: " " });
36
+ expect(span.textContent).toBe("\u2423\u2423\u2423");
37
+ expect(span.getAttribute("aria-label")).toBe("3 spaces");
38
+ });
39
+
40
+ it("renders tab", () => {
41
+ const span = renderSentinel({ type: "whitespace", value: "\t" });
42
+ expect(span.textContent).toBe("\\t");
43
+ expect(span.getAttribute("aria-label")).toBe("1 tab");
44
+ });
45
+
46
+ it("renders newline", () => {
47
+ const span = renderSentinel({ type: "whitespace", value: "\n" });
48
+ expect(span.textContent).toBe("\\n");
49
+ expect(span.getAttribute("aria-label")).toBe("1 newline");
50
+ });
51
+
52
+ it("renders mixed whitespace", () => {
53
+ const span = renderSentinel({ type: "whitespace", value: "\t \n" });
54
+ expect(span.textContent).toBe("\\t\u2423\\n");
55
+ expect(span.getAttribute("aria-label")).toBe("1 tab, 1 space, 1 newline");
56
+ });
57
+
58
+ it("renders NaN", () => {
59
+ const span = renderSentinel({ type: "nan", value: Number.NaN });
60
+ expect(span.textContent).toBe("NaN");
61
+ });
62
+
63
+ it("renders inf", () => {
64
+ const span = renderSentinel({ type: "positive-infinity", value: Infinity });
65
+ expect(span.textContent).toBe("inf");
66
+ expect(span.getAttribute("title")).toBe("Infinity");
67
+ });
68
+
69
+ it("renders -inf", () => {
70
+ const span = renderSentinel({
71
+ type: "negative-infinity",
72
+ value: -Infinity,
73
+ });
74
+ expect(span.textContent).toBe("-inf");
75
+ expect(span.getAttribute("title")).toBe("-Infinity");
76
+ });
77
+
78
+ it("renders NaT", () => {
79
+ const span = renderSentinel({ type: "nat", value: "NaT" });
80
+ expect(span.textContent).toBe("NaT");
81
+ expect(span.getAttribute("title")).toBe("NaT (Not a Time)");
82
+ });
83
+ });
@@ -3,6 +3,7 @@
3
3
  import type { Table } from "@tanstack/react-table";
4
4
  import { describe, expect, it } from "vitest";
5
5
  import {
6
+ detectSentinel,
6
7
  getClipboardContent,
7
8
  getPageIndexForRow,
8
9
  getRawValue,
@@ -186,6 +187,133 @@ describe("getClipboardContent", () => {
186
187
  });
187
188
  });
188
189
 
190
+ describe("detectSentinel", () => {
191
+ it("should detect null and undefined", () => {
192
+ expect(detectSentinel(null, undefined)).toEqual({
193
+ type: "null",
194
+ value: null,
195
+ });
196
+ expect(detectSentinel(undefined, undefined)).toEqual({
197
+ type: "null",
198
+ value: undefined,
199
+ });
200
+ });
201
+
202
+ it("should detect empty string", () => {
203
+ expect(detectSentinel("", "string")).toEqual({
204
+ type: "empty-string",
205
+ value: "",
206
+ });
207
+ });
208
+
209
+ it("should detect whitespace-only strings", () => {
210
+ expect(detectSentinel(" ", "string")).toEqual({
211
+ type: "whitespace",
212
+ value: " ",
213
+ });
214
+ expect(detectSentinel(" ", "string")).toEqual({
215
+ type: "whitespace",
216
+ value: " ",
217
+ });
218
+ expect(detectSentinel("\t", "string")).toEqual({
219
+ type: "whitespace",
220
+ value: "\t",
221
+ });
222
+ expect(detectSentinel("\n", "string")).toEqual({
223
+ type: "whitespace",
224
+ value: "\n",
225
+ });
226
+ expect(detectSentinel("\t \n", "string")).toEqual({
227
+ type: "whitespace",
228
+ value: "\t \n",
229
+ });
230
+ });
231
+
232
+ it("should detect NaN", () => {
233
+ expect(detectSentinel(Number.NaN, "number")).toEqual({
234
+ type: "nan",
235
+ value: Number.NaN,
236
+ });
237
+ });
238
+
239
+ it("should detect Infinity", () => {
240
+ expect(detectSentinel(Number.POSITIVE_INFINITY, "number")).toEqual({
241
+ type: "positive-infinity",
242
+ value: Number.POSITIVE_INFINITY,
243
+ });
244
+ expect(detectSentinel(Number.NEGATIVE_INFINITY, "number")).toEqual({
245
+ type: "negative-infinity",
246
+ value: Number.NEGATIVE_INFINITY,
247
+ });
248
+ });
249
+
250
+ it("should return null for normal values", () => {
251
+ expect(detectSentinel("hello", "string")).toBeNull();
252
+ expect(detectSentinel(42, "number")).toBeNull();
253
+ expect(detectSentinel(0, "number")).toBeNull();
254
+ expect(detectSentinel(-1.5, "number")).toBeNull();
255
+ expect(detectSentinel(true, "boolean")).toBeNull();
256
+ expect(detectSentinel(false, "boolean")).toBeNull();
257
+ expect(detectSentinel({}, "unknown")).toBeNull();
258
+ expect(detectSentinel([], "unknown")).toBeNull();
259
+ });
260
+
261
+ it("should not match literal null-like strings", () => {
262
+ expect(detectSentinel("null", "string")).toBeNull();
263
+ expect(detectSentinel("NULL", "string")).toBeNull();
264
+ expect(detectSentinel("None", "string")).toBeNull();
265
+ });
266
+
267
+ it("should not match string NaN/Infinity in non-numeric columns", () => {
268
+ expect(detectSentinel("NaN", "string")).toBeNull();
269
+ expect(detectSentinel("Infinity", "string")).toBeNull();
270
+ expect(detectSentinel("-Infinity", "string")).toBeNull();
271
+ });
272
+
273
+ it("should match string NaN/Infinity in numeric columns", () => {
274
+ expect(detectSentinel("NaN", "number")).toEqual({
275
+ type: "nan",
276
+ value: "NaN",
277
+ });
278
+ expect(detectSentinel("Infinity", "number")).toEqual({
279
+ type: "positive-infinity",
280
+ value: "Infinity",
281
+ });
282
+ expect(detectSentinel("-Infinity", "number")).toEqual({
283
+ type: "negative-infinity",
284
+ value: "-Infinity",
285
+ });
286
+ expect(detectSentinel("inf", "number")).toEqual({
287
+ type: "positive-infinity",
288
+ value: "inf",
289
+ });
290
+ expect(detectSentinel("-inf", "number")).toEqual({
291
+ type: "negative-infinity",
292
+ value: "-inf",
293
+ });
294
+ });
295
+
296
+ it("should still not match normal strings in numeric columns", () => {
297
+ expect(detectSentinel("hello", "number")).toBeNull();
298
+ expect(detectSentinel("42", "number")).toBeNull();
299
+ });
300
+
301
+ it("should not match NaT in non-temporal columns", () => {
302
+ expect(detectSentinel("NaT", "string")).toBeNull();
303
+ });
304
+
305
+ it("should match NaT in temporal columns", () => {
306
+ expect(detectSentinel("NaT", "datetime")).toEqual({
307
+ type: "nat",
308
+ value: "NaT",
309
+ });
310
+ expect(detectSentinel("NaT", "date")).toEqual({
311
+ type: "nat",
312
+ value: "NaT",
313
+ });
314
+ });
315
+ });
316
+
189
317
  function createMockTableWithMeta<TData>(rawData?: TData[]): Table<TData> {
190
318
  return {
191
319
  options: {
@@ -53,6 +53,7 @@ import {
53
53
  SelectValue,
54
54
  } from "../ui/select";
55
55
  import { type ColumnFilterForType, Filter } from "./filters";
56
+ import { SentinelCell } from "./sentinel-cell";
56
57
  import {
57
58
  ClearFilterMenuItem,
58
59
  FilterButtons,
@@ -65,7 +66,7 @@ import {
65
66
  renderSortFilterIcon,
66
67
  renderSorts,
67
68
  } from "./header-items";
68
- import { stringifyUnknownValue } from "./utils";
69
+ import { detectSentinel, stringifyUnknownValue } from "./utils";
69
70
 
70
71
  const TOP_K_ROWS = 30;
71
72
 
@@ -647,6 +648,10 @@ const PopoverFilterByValues = <TData, TValue>({
647
648
  {filteredData.map(([value, count], rowIndex) => {
648
649
  const isSelected = chosenValues.has(value);
649
650
  const valueString = stringifyUnknownValue({ value });
651
+ const sentinel = detectSentinel(
652
+ value,
653
+ column.columnDef.meta?.dataType,
654
+ );
650
655
 
651
656
  return (
652
657
  <CommandItem
@@ -661,7 +666,11 @@ const PopoverFilterByValues = <TData, TValue>({
661
666
  className="mr-3 h-3.5 w-3.5"
662
667
  />
663
668
  <span className="flex-1 overflow-hidden max-h-20 line-clamp-3">
664
- {valueString}
669
+ {sentinel ? (
670
+ <SentinelCell sentinel={sentinel} />
671
+ ) : (
672
+ valueString
673
+ )}
665
674
  </span>
666
675
  <span className="ml-3">{count}</span>
667
676
  </CommandItem>
@@ -37,7 +37,10 @@ import {
37
37
  extractTimezone,
38
38
  type FieldTypesWithExternalType,
39
39
  INDEX_COLUMN_NAME,
40
+ isNumericType,
40
41
  } from "./types";
42
+ import { SentinelCell } from "./sentinel-cell";
43
+ import { detectSentinel } from "./utils";
41
44
  import { uniformSample } from "./uniformSample";
42
45
  import { MarkdownUrlDetector, UrlDetector } from "./url-detector";
43
46
 
@@ -163,7 +166,7 @@ export function generateColumns<T>({
163
166
  }
164
167
  // Auto right-align numeric columns
165
168
  const dataType = getMeta(key).dataType;
166
- if (dataType === "number" || dataType === "integer") {
169
+ if (isNumericType(dataType)) {
167
170
  return "right";
168
171
  }
169
172
  return undefined;
@@ -269,7 +272,7 @@ export function generateColumns<T>({
269
272
  !isCellSelected;
270
273
 
271
274
  const dataType = column.columnDef.meta?.dataType;
272
- const isNumeric = dataType === "number" || dataType === "integer";
275
+ const isNumeric = isNumericType(dataType);
273
276
  const cellStyles = getCellStyleClass({
274
277
  justify,
275
278
  wrapped,
@@ -522,6 +525,17 @@ export function renderCellValue<TData, TValue>({
522
525
 
523
526
  const isWrapped = column.getColumnWrapping?.() === "wrap";
524
527
 
528
+ // Sentinel values (null, whitespace, NaN, Infinity, NaT) rendered specially.
529
+ // Empty strings are left as-is
530
+ const sentinel = detectSentinel(value, dataType);
531
+ if (sentinel && sentinel.type !== "empty-string") {
532
+ return (
533
+ <div onClick={selectCell} className={cellStyles}>
534
+ <SentinelCell sentinel={sentinel} />
535
+ </div>
536
+ );
537
+ }
538
+
525
539
  if (dataType === "datetime" && typeof value === "string") {
526
540
  try {
527
541
  if (!isValid(value)) {
@@ -0,0 +1,90 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import type { CellValueSentinel, CellValueSentinelType } from "./types";
4
+
5
+ const WHITESPACE_CHARS: Record<string, { marker: string; name: string }> = {
6
+ " ": { marker: "\u2423", name: "space" }, // open box (space symbol)
7
+ "\t": { marker: "\\t", name: "tab" },
8
+ "\n": { marker: "\\n", name: "newline" },
9
+ "\r": { marker: "\\r", name: "newline" },
10
+ };
11
+
12
+ function renderWhitespaceMarkers(str: string): string {
13
+ return [...str].map((ch) => WHITESPACE_CHARS[ch]?.marker ?? ch).join("");
14
+ }
15
+
16
+ function describeWhitespace(str: string): string {
17
+ const counts: Record<string, number> = {};
18
+ for (const ch of str) {
19
+ const name = WHITESPACE_CHARS[ch]?.name ?? "character";
20
+ counts[name] = (counts[name] ?? 0) + 1;
21
+ }
22
+ return Object.entries(counts)
23
+ .map(([name, count]) => `${count} ${name}${count > 1 ? "s" : ""}`)
24
+ .join(", ");
25
+ }
26
+
27
+ interface SentinelConfig {
28
+ label: (value: CellValueSentinel["value"]) => string;
29
+ tooltip: (value: CellValueSentinel["value"]) => string;
30
+ ariaLabel: (value: CellValueSentinel["value"]) => string;
31
+ }
32
+
33
+ const SENTINEL_CONFIG: Record<CellValueSentinelType, SentinelConfig> = {
34
+ null: {
35
+ label: () => "None",
36
+ tooltip: () => "None",
37
+ ariaLabel: () => "None",
38
+ },
39
+ "empty-string": {
40
+ label: () => "<empty>",
41
+ tooltip: () => "<empty>",
42
+ ariaLabel: () => "empty string",
43
+ },
44
+ whitespace: {
45
+ label: (value) => renderWhitespaceMarkers(String(value)),
46
+ tooltip: (value) => describeWhitespace(String(value)),
47
+ ariaLabel: (value) => describeWhitespace(String(value)),
48
+ },
49
+ nan: {
50
+ label: () => "NaN",
51
+ tooltip: () => "NaN",
52
+ ariaLabel: () => "NaN",
53
+ },
54
+ "positive-infinity": {
55
+ label: () => "inf",
56
+ tooltip: () => "Infinity",
57
+ ariaLabel: () => "infinity",
58
+ },
59
+ "negative-infinity": {
60
+ label: () => "-inf",
61
+ tooltip: () => "-Infinity",
62
+ ariaLabel: () => "negative infinity",
63
+ },
64
+ nat: {
65
+ label: () => "NaT",
66
+ tooltip: () => "NaT (Not a Time)",
67
+ ariaLabel: () => "Not a Time",
68
+ },
69
+ };
70
+
71
+ export function SentinelCell({
72
+ sentinel,
73
+ }: {
74
+ sentinel: CellValueSentinel;
75
+ }): React.ReactElement {
76
+ const config = SENTINEL_CONFIG[sentinel.type];
77
+ const label = config.label(sentinel.value);
78
+ const tooltip = config.tooltip(sentinel.value);
79
+ const ariaLabel = config.ariaLabel(sentinel.value);
80
+
81
+ return (
82
+ <span
83
+ className="italic text-muted-foreground bg-muted rounded px-1"
84
+ aria-label={ariaLabel}
85
+ title={tooltip}
86
+ >
87
+ <span className="opacity-70">{label}</span>
88
+ </span>
89
+ );
90
+ }
@@ -95,6 +95,29 @@ export type DataTableSelection =
95
95
  | "multi-cell"
96
96
  | null;
97
97
 
98
+ export type CellValueSentinel =
99
+ | { type: "null"; value: null | undefined }
100
+ | { type: "empty-string"; value: string }
101
+ | { type: "whitespace"; value: string }
102
+ | { type: "nan"; value: number | string }
103
+ | { type: "positive-infinity"; value: number | string }
104
+ | { type: "negative-infinity"; value: number | string }
105
+ | { type: "nat"; value: string };
106
+
107
+ export type CellValueSentinelType = CellValueSentinel["type"];
108
+
109
+ export function isNumericType(
110
+ dataType: DataType | undefined,
111
+ ): dataType is "number" | "integer" {
112
+ return dataType === "number" || dataType === "integer";
113
+ }
114
+
115
+ export function isTemporalType(
116
+ dataType: DataType | undefined,
117
+ ): dataType is "date" | "datetime" | "time" {
118
+ return dataType === "date" || dataType === "datetime" || dataType === "time";
119
+ }
120
+
98
121
  export function extractTimezone(dtype: string | undefined): string | undefined {
99
122
  if (!dtype) {
100
123
  return undefined;
@@ -5,7 +5,15 @@ import type { TableData } from "@/plugins/impl/DataTablePlugin";
5
5
  import { vegaLoadData } from "@/plugins/impl/vega/loader";
6
6
  import { jsonParseWithSpecialChar } from "@/utils/json/json-parser";
7
7
  import { getMimeValues } from "./mime-cell";
8
- import { INDEX_COLUMN_NAME } from "./types";
8
+ import type { DataType } from "@/core/kernel/messages";
9
+ import {
10
+ type CellValueSentinel,
11
+ INDEX_COLUMN_NAME,
12
+ isNumericType,
13
+ isTemporalType,
14
+ } from "./types";
15
+
16
+ const WHITESPACE_ONLY_RE = /^[\s]+$/;
9
17
 
10
18
  /**
11
19
  * Convenience function to load table data.
@@ -85,6 +93,71 @@ export function getPageIndexForRow(
85
93
  return null;
86
94
  }
87
95
 
96
+ // String representations of numeric special values.
97
+ // Only matched when the caller indicates the column is numeric.
98
+ type StringValueSentinelType = Extract<
99
+ CellValueSentinel,
100
+ { value: number | string }
101
+ >["type"];
102
+
103
+ const NUMERIC_STRING_SPECIALS: Record<string, StringValueSentinelType> = {
104
+ NaN: "nan",
105
+ Infinity: "positive-infinity",
106
+ "-Infinity": "negative-infinity",
107
+ inf: "positive-infinity",
108
+ "-inf": "negative-infinity",
109
+ };
110
+
111
+ /**
112
+ * Detect if a cell value is a sentinel (null, empty string, whitespace,
113
+ * NaN, infinity, NaT). Column-type-dependent sentinels (string "NaN",
114
+ * "NaT", etc.) are matched based on `dataType`.
115
+ */
116
+ export function detectSentinel(
117
+ value: unknown,
118
+ dataType: DataType | undefined,
119
+ ): CellValueSentinel | null {
120
+ if (value == null) {
121
+ return { type: "null", value };
122
+ }
123
+
124
+ if (typeof value === "string") {
125
+ if (value === "") {
126
+ return { type: "empty-string", value };
127
+ }
128
+ if (WHITESPACE_ONLY_RE.test(value)) {
129
+ return { type: "whitespace", value };
130
+ }
131
+ // String "NaN"/"Infinity" in a numeric column = actual special float value
132
+ if (isNumericType(dataType)) {
133
+ const type = NUMERIC_STRING_SPECIALS[value];
134
+ if (type) {
135
+ return { type, value };
136
+ }
137
+ }
138
+ // String "NaT" in a temporal column = pandas Not-a-Time sentinel
139
+ if (isTemporalType(dataType) && value === "NaT") {
140
+ return { type: "nat", value };
141
+ }
142
+ return null;
143
+ }
144
+
145
+ if (typeof value === "number") {
146
+ if (Number.isNaN(value)) {
147
+ return { type: "nan", value };
148
+ }
149
+ if (value === Number.POSITIVE_INFINITY) {
150
+ return { type: "positive-infinity", value };
151
+ }
152
+ if (value === Number.NEGATIVE_INFINITY) {
153
+ return { type: "negative-infinity", value };
154
+ }
155
+ return null;
156
+ }
157
+
158
+ return null;
159
+ }
160
+
88
161
  /**
89
162
  * Stringify an unknown value. Converts objects to JSON strings.
90
163
  * @param opts.value - The value to stringify.