@marimo-team/islands 0.23.7-dev5 → 0.23.7-dev7

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.
@@ -8,7 +8,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
9
  import "./html-to-image-hMMPiNe_.js";
10
10
  import "./chunk-5FQGJX7Z-CO1e63h_.js";
11
- import { Ft as Code, Mt as Expand, a as DEFAULT_SLIDE_TYPE, c as Slide, i as DEFAULT_DECK_TRANSITION, jt as EyeOff, s as SlideSidebar, t as useNotebookCodeAvailable } from "./code-visibility-D8E8Ctez.js";
11
+ import { Ft as Code, Mt as Expand, a as DEFAULT_SLIDE_TYPE, c as Slide, i as DEFAULT_DECK_TRANSITION, jt as EyeOff, s as SlideSidebar, t as useNotebookCodeAvailable } from "./code-visibility-CiN3Xnfo.js";
12
12
  import "./input-BAOe64zx.js";
13
13
  import "./toDate-CHtl9vts.js";
14
14
  import "./react-dom-BWRJ_g_k.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.23.7-dev5",
3
+ "version": "0.23.7-dev7",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -34,6 +34,7 @@ interface TableTopBarProps extends Partial<ExportActionProps> {
34
34
  showTableExplorer?: boolean;
35
35
  togglePanel?: (panelType: PanelType) => void;
36
36
  isAnyPanelOpen?: boolean;
37
+ sizeBytes?: number | null;
37
38
  }
38
39
 
39
40
  export const TableTopBar: React.FC<TableTopBarProps> = ({
@@ -48,6 +49,7 @@ export const TableTopBar: React.FC<TableTopBarProps> = ({
48
49
  togglePanel,
49
50
  isAnyPanelOpen,
50
51
  downloadAs,
52
+ sizeBytes,
51
53
  }) => {
52
54
  const [internalValue, setInternalValue] = useState(searchQuery || "");
53
55
  const debouncedSearch = useDebounce(internalValue, 500);
@@ -130,7 +132,9 @@ export const TableTopBar: React.FC<TableTopBarProps> = ({
130
132
  Explore
131
133
  </Button>
132
134
  )}
133
- {downloadAs && <ExportMenu downloadAs={downloadAs} />}
135
+ {downloadAs && (
136
+ <ExportMenu downloadAs={downloadAs} sizeBytes={sizeBytes} />
137
+ )}
134
138
  </div>
135
139
  </div>
136
140
  );
@@ -70,6 +70,9 @@ interface DataTableProps<TData> extends Partial<ExportActionProps> {
70
70
  setSorting?: OnChangeFn<SortingState>; // controlled sorting
71
71
  // Pagination
72
72
  totalRows: number | TooManyRows;
73
+ // JSON-serialized size of the currently-rendered data. Forwarded to
74
+ // ExportMenu so hosts can size-gate the Export button via downloadSizeLimitAtom.
75
+ sizeBytes?: number | null;
73
76
  totalColumns: number;
74
77
  pagination?: boolean;
75
78
  manualPagination?: boolean; // server-side pagination
@@ -121,6 +124,7 @@ const DataTableInternal = <TData,>({
121
124
  selection,
122
125
  totalColumns,
123
126
  totalRows,
127
+ sizeBytes,
124
128
  manualSorting = false,
125
129
  sorting,
126
130
  setSorting,
@@ -309,6 +313,7 @@ const DataTableInternal = <TData,>({
309
313
  togglePanel={togglePanel}
310
314
  isAnyPanelOpen={isAnyPanelOpen}
311
315
  downloadAs={downloadAs}
316
+ sizeBytes={sizeBytes}
312
317
  />
313
318
  <Table
314
319
  className={cn(
@@ -0,0 +1,10 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { atom } from "jotai";
4
+
5
+ export interface DownloadSizeLimit {
6
+ limitBytes: number;
7
+ unavailableMessage: string;
8
+ }
9
+
10
+ export const downloadSizeLimitAtom = atom<DownloadSizeLimit | null>(null);
@@ -1,5 +1,6 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
+ import { useAtomValue } from "jotai";
3
4
  import {
4
5
  BracesIcon,
5
6
  BrickWallIcon,
@@ -9,6 +10,7 @@ import {
9
10
  } from "lucide-react";
10
11
  import React from "react";
11
12
  import { useLocale } from "react-aria";
13
+ import { downloadSizeLimitAtom } from "./download-policy/atoms";
12
14
  import { logNever } from "@/utils/assertNever";
13
15
  import { cn } from "@/utils/cn";
14
16
  import { copyToClipboard } from "@/utils/copy";
@@ -84,6 +86,11 @@ export interface ExportActionProps {
84
86
  error?: string | null;
85
87
  missing_packages?: string[] | null;
86
88
  }>;
89
+ // JSON-serialized size of the currently-rendered data. Used together with
90
+ // downloadSizeLimitAtom to disable the Export button when a host (e.g.,
91
+ // marimo-lsp inside VS Code) declares a download size cap. Null/undefined
92
+ // means "no info" and the gate stays disabled (fail-open).
93
+ sizeBytes?: number | null;
87
94
  }
88
95
 
89
96
  const labelForDownloadFormat = (format: DownloadFormat): string =>
@@ -94,12 +101,19 @@ const labelForCopyFormat = (format: CopyFormat): string =>
94
101
  export const ExportMenu: React.FC<ExportActionProps> = (props) => {
95
102
  const { locale } = useLocale();
96
103
  const [open, setOpen] = React.useState(false);
104
+ const policy = useAtomValue(downloadSizeLimitAtom);
105
+ const disabled = !!(
106
+ policy &&
107
+ props.sizeBytes != null &&
108
+ props.sizeBytes > policy.limitBytes
109
+ );
97
110
 
98
111
  const button = (
99
112
  <Button
100
113
  data-testid="export-button"
101
114
  size="xs"
102
115
  variant="text"
116
+ disabled={disabled}
103
117
  className={cn(
104
118
  "print:hidden text-xs gap-1",
105
119
  open ? "text-primary" : "text-muted-foreground",
@@ -113,7 +127,10 @@ export const ExportMenu: React.FC<ExportActionProps> = (props) => {
113
127
  const resolveDownloadUrl = async (
114
128
  format: DownloadFormat,
115
129
  onRetry: () => void,
116
- ): Promise<{ url: string; filename: string } | null> => {
130
+ ): Promise<{
131
+ url: string;
132
+ filename: string;
133
+ } | null> => {
117
134
  let response: Awaited<ReturnType<typeof props.downloadAs>>;
118
135
  try {
119
136
  response = await props.downloadAs({ format });
@@ -143,7 +160,10 @@ export const ExportMenu: React.FC<ExportActionProps> = (props) => {
143
160
  return null;
144
161
  }
145
162
 
146
- return { url: response.url, filename: response.filename };
163
+ return {
164
+ url: response.url,
165
+ filename: response.filename,
166
+ };
147
167
  };
148
168
 
149
169
  const handleDownload = async (format: DownloadFormat) => {
@@ -229,8 +249,15 @@ export const ExportMenu: React.FC<ExportActionProps> = (props) => {
229
249
 
230
250
  return (
231
251
  <DropdownMenu modal={false} open={open} onOpenChange={setOpen}>
232
- <Tooltip content="Export" open={open ? false : undefined}>
233
- <DropdownMenuTrigger asChild={true}>{button}</DropdownMenuTrigger>
252
+ <Tooltip
253
+ content={disabled ? policy?.unavailableMessage : "Export"}
254
+ open={open ? false : undefined}
255
+ >
256
+ <DropdownMenuTrigger asChild={true} disabled={disabled}>
257
+ <span tabIndex={disabled ? 0 : -1} className="inline-flex">
258
+ {button}
259
+ </span>
260
+ </DropdownMenuTrigger>
234
261
  </Tooltip>
235
262
  <DropdownMenuContent side="bottom" className="print:hidden">
236
263
  <DropdownMenuLabel className="text-xs text-muted-foreground">
@@ -194,6 +194,7 @@ interface Data<T> {
194
194
  wrappedColumns?: string[];
195
195
  headerTooltip?: Record<string, string>;
196
196
  totalColumns: number;
197
+ sizeBytes?: number | null;
197
198
  maxColumns: number | "all";
198
199
  hasStableRowId: boolean;
199
200
  lazy: boolean;
@@ -220,6 +221,7 @@ type DataTableFunctions = {
220
221
  cell_styles?: CellStyleState | null;
221
222
  cell_hover_texts?: Record<string, Record<string, string | null>> | null;
222
223
  raw_data?: TableData<T> | null;
224
+ size_bytes?: number | null;
223
225
  }>;
224
226
  get_data_url?: GetDataUrl;
225
227
  get_row_ids?: GetRowIds;
@@ -270,6 +272,7 @@ export const DataTablePlugin = createPlugin<S>("marimo-table")
270
272
  headerTooltip: z.record(z.string(), z.string()).optional(),
271
273
  fieldTypes: columnToFieldTypesSchema.nullish(),
272
274
  totalColumns: z.number(),
275
+ sizeBytes: z.number().nullish(),
273
276
  maxColumns: z.union([z.number(), z.literal("all")]).default("all"),
274
277
  hasStableRowId: z.boolean().default(false),
275
278
  maxHeight: z.number().optional(),
@@ -327,6 +330,7 @@ export const DataTablePlugin = createPlugin<S>("marimo-table")
327
330
  .nullable(),
328
331
  cell_hover_texts: cellHoverTextSchema.nullable(),
329
332
  raw_data: z.union([z.string(), z.array(z.looseObject({}))]).nullish(),
333
+ size_bytes: z.number().nullish(),
330
334
  }),
331
335
  ),
332
336
  get_row_ids: rpc.input(z.object({}).passthrough()).output(
@@ -532,6 +536,7 @@ export const LoadingDataTableComponent = memo(
532
536
  rows: T[];
533
537
  rawRows?: T[];
534
538
  totalRows: number | TooManyRows;
539
+ sizeBytes?: number | null;
535
540
  cellStyles: CellStyleState | undefined | null;
536
541
  cellHoverTexts?: Record<string, Record<string, string | null>> | null;
537
542
  }>(async () => {
@@ -548,6 +553,7 @@ export const LoadingDataTableComponent = memo(
548
553
  let tableData = props.data;
549
554
  let rawTableData: TableData<T> | undefined | null = props.rawData;
550
555
  let totalRows = props.totalRows;
556
+ let sizeBytes = props.sizeBytes ?? null;
551
557
  let cellStyles = props.cellStyles;
552
558
  let cellHoverTexts = props.cellHoverTexts;
553
559
 
@@ -591,6 +597,7 @@ export const LoadingDataTableComponent = memo(
591
597
  tableData = searchResults.data;
592
598
  rawTableData = searchResults.raw_data;
593
599
  totalRows = searchResults.total_rows;
600
+ sizeBytes = searchResults.size_bytes ?? null;
594
601
  cellStyles = searchResults.cell_styles || {};
595
602
  cellHoverTexts = searchResults.cell_hover_texts || {};
596
603
  }
@@ -603,6 +610,7 @@ export const LoadingDataTableComponent = memo(
603
610
  rows: tableData,
604
611
  rawRows: rawData,
605
612
  totalRows: totalRows,
613
+ sizeBytes,
606
614
  cellStyles,
607
615
  cellHoverTexts,
608
616
  };
@@ -614,6 +622,7 @@ export const LoadingDataTableComponent = memo(
614
622
  useDeepCompareMemoize(props.fieldTypes),
615
623
  props.data,
616
624
  props.totalRows,
625
+ props.sizeBytes,
617
626
  props.lazy,
618
627
  props.cellHoverTexts,
619
628
  props.cellStyles,
@@ -728,6 +737,7 @@ export const LoadingDataTableComponent = memo(
728
737
  setFilters={setFilters}
729
738
  reloading={isFetching && !isPending}
730
739
  totalRows={data?.totalRows ?? props.totalRows}
740
+ sizeBytes={data?.sizeBytes ?? props.sizeBytes ?? null}
731
741
  paginationState={paginationState}
732
742
  setPaginationState={setPaginationState}
733
743
  cellStyles={data?.cellStyles ?? props.cellStyles}
@@ -774,6 +784,7 @@ const DataTableComponent = ({
774
784
  data,
775
785
  rawData,
776
786
  totalRows,
787
+ sizeBytes,
777
788
  maxColumns,
778
789
  pagination,
779
790
  selection,
@@ -1053,6 +1064,7 @@ const DataTableComponent = ({
1053
1064
  maxHeight={maxHeight}
1054
1065
  sorting={sorting}
1055
1066
  totalRows={totalRows}
1067
+ sizeBytes={sizeBytes}
1056
1068
  totalColumns={totalColumns}
1057
1069
  manualSorting={true}
1058
1070
  setSorting={setSorting}
@@ -64,6 +64,7 @@ type PluginFunctions = {
64
64
  column_types_per_step: FieldTypesWithExternalType[];
65
65
  python_code?: string | null;
66
66
  sql_code?: string | null;
67
+ size_bytes?: number | null;
67
68
  }>;
68
69
  get_column_values: (req: { column: string }) => Promise<{
69
70
  values: unknown[];
@@ -81,6 +82,7 @@ type PluginFunctions = {
81
82
  }) => Promise<{
82
83
  data: TableData<T>;
83
84
  total_rows: number;
85
+ size_bytes?: number | null;
84
86
  }>;
85
87
  download_as: DownloadAsArgs;
86
88
  };
@@ -118,6 +120,7 @@ export const DataFramePlugin = createPlugin<S>("marimo-dataframe")
118
120
  column_types_per_step: z.array(columnToFieldTypesSchema),
119
121
  python_code: z.string().nullish(),
120
122
  sql_code: z.string().nullish(),
123
+ size_bytes: z.number().nullish(),
121
124
  }),
122
125
  ),
123
126
  get_column_values: rpc.input(z.object({ column: z.string() })).output(
@@ -147,6 +150,7 @@ export const DataFramePlugin = createPlugin<S>("marimo-dataframe")
147
150
  z.object({
148
151
  data: z.union([z.string(), z.array(z.object({}).passthrough())]),
149
152
  total_rows: z.number(),
153
+ size_bytes: z.number().nullish(),
150
154
  }),
151
155
  ),
152
156
  download_as: DownloadAsSchema,
@@ -203,6 +207,7 @@ export const DataFrameComponent = memo(
203
207
  column_types_per_step,
204
208
  python_code,
205
209
  sql_code,
210
+ size_bytes,
206
211
  } = data || {};
207
212
 
208
213
  const totalColumns = field_types?.length;
@@ -322,6 +327,7 @@ export const DataFrameComponent = memo(
322
327
  data={url || ""}
323
328
  hasStableRowId={false}
324
329
  totalRows={total_rows ?? 0}
330
+ sizeBytes={size_bytes ?? null}
325
331
  totalColumns={totalColumns ?? 0}
326
332
  maxColumns="all"
327
333
  pageSize={pageSize}