@marimo-team/islands 0.23.2-dev2 → 0.23.2-dev20

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 (84) hide show
  1. package/dist/_basePickBy-C-mod5Dp.js +34 -0
  2. package/dist/{_baseUniq-C87CckHL.js → _baseUniq-Be_p_Ty6.js} +2 -2
  3. package/dist/{architecture-7HQA4BMR-BHdkAMvZ.js → architecture-7HQA4BMR-kNyKQXbB.js} +2 -2
  4. package/dist/{architectureDiagram-VXUJARFQ-B3YQo9At.js → architectureDiagram-VXUJARFQ-Dx_Dniiw.js} +11 -11
  5. package/dist/{blockDiagram-VD42YOAC-CpQ3TKEN.js → blockDiagram-VD42YOAC-D3hGPvEt.js} +4 -4
  6. package/dist/{c4Diagram-YG6GDRKO-CZSU4uqU.js → c4Diagram-YG6GDRKO-CtY1WMbV.js} +1 -1
  7. package/dist/{chat-ui-CNHw9Osh.js → chat-ui-DIVMRPO5.js} +2 -2
  8. package/dist/{chunk-4F5CHEZ2-D5mClyDv.js → chunk-4F5CHEZ2-oWcaQSBe.js} +1 -1
  9. package/dist/{chunk-B2363JML-Br0eA2T3.js → chunk-B2363JML-72CRxZbk.js} +1 -1
  10. package/dist/{chunk-B4BG7PRW-4BjV11Br.js → chunk-B4BG7PRW-ChYfc4rf.js} +2 -2
  11. package/dist/{chunk-DI55MBZ5-DITY3EyP.js → chunk-DI55MBZ5-CYNE3N2j.js} +2 -2
  12. package/dist/{chunk-FRFDVMJY-DnEvEFRR.js → chunk-FRFDVMJY-Dgl-7l0K.js} +1 -1
  13. package/dist/{chunk-JA3XYJ7Z-BcPEfxk_.js → chunk-JA3XYJ7Z-B2BoMdpr.js} +1 -1
  14. package/dist/{chunk-JZLCHNYA-2bnLL3xL.js → chunk-JZLCHNYA-CkHD9mQU.js} +2 -2
  15. package/dist/{chunk-N4CR4FBY-CpZSuGSU.js → chunk-N4CR4FBY-DDeXUk3y.js} +4 -4
  16. package/dist/{chunk-PL6DKKU2-DnId6G-x.js → chunk-PL6DKKU2-CpBHhdj8.js} +1 -1
  17. package/dist/{chunk-QXUST7PY-Ch6F5Obl.js → chunk-QXUST7PY-BnSZbSK7.js} +3 -3
  18. package/dist/{chunk-S3R3BYOJ-B0UOFJwq.js → chunk-S3R3BYOJ-DVdRer7T.js} +1 -1
  19. package/dist/{chunk-SJTYNZTY-BsBZnJUj.js → chunk-SJTYNZTY-DPOwAZc-.js} +1 -1
  20. package/dist/{chunk-TCCFYFTB-Clbl-fTg.js → chunk-TCCFYFTB-BdE6BTq1.js} +6 -6
  21. package/dist/{chunk-TQ3KTPDO-CFkSQ30e.js → chunk-TQ3KTPDO-BCXCq8f2.js} +1 -1
  22. package/dist/{chunk-UMXZTB3W-D-A834Bq.js → chunk-UMXZTB3W-C5Hu2atA.js} +1 -1
  23. package/dist/{classDiagram-v2-WZHVMYZB-DrmbGANl.js → classDiagram-2ON5EDUG-sUXB0Obe.js} +6 -6
  24. package/dist/{classDiagram-2ON5EDUG-C8-zE3Zv.js → classDiagram-v2-WZHVMYZB-JeF9-idj.js} +6 -6
  25. package/dist/{clone-DZFQCtFJ.js → clone-B48LSK6I.js} +1 -1
  26. package/dist/{dagre-6UL2VRFP-OMItEBnY.js → dagre-6UL2VRFP-Bs_DhCUk.js} +9 -9
  27. package/dist/{dagre-QVd-lCXU.js → dagre-BLW2E2fh.js} +19 -8
  28. package/dist/{diagram-PSM6KHXK-CkKbohWI.js → diagram-PSM6KHXK-VB3japmQ.js} +10 -10
  29. package/dist/{diagram-QEK2KX5R-DjUMpVcx.js → diagram-QEK2KX5R-B8nm2JL9.js} +10 -10
  30. package/dist/{diagram-S2PKOQOG-b-c0d-wZ.js → diagram-S2PKOQOG-D6PR_2iv.js} +10 -10
  31. package/dist/{erDiagram-Q2GNP2WA-CDhLaOZ1.js → erDiagram-Q2GNP2WA-gjAse7Jb.js} +5 -5
  32. package/dist/{flowDiagram-NV44I4VS-BDi4O4CL.js → flowDiagram-NV44I4VS-CQTSZWcI.js} +5 -5
  33. package/dist/{ganttDiagram-JELNMOA3-BpZE6kVp.js → ganttDiagram-JELNMOA3-aktqk_om.js} +1 -1
  34. package/dist/{gitGraph-G5XIXVHT-B_c6xFJv.js → gitGraph-G5XIXVHT-Cy06nzLg.js} +2 -2
  35. package/dist/{gitGraphDiagram-V2S2FVAM-iQnXzbPM.js → gitGraphDiagram-V2S2FVAM-C1ntKO33.js} +10 -10
  36. package/dist/{graphlib-BV1_gi0C.js → graphlib-Cr691-na.js} +3 -3
  37. package/dist/{hasIn-DnfJcYpY.js → hasIn-BDDmuo1w.js} +1 -1
  38. package/dist/{info-VBDWY6EO-BTyzxmhr.js → info-VBDWY6EO-BIO6A8nW.js} +2 -2
  39. package/dist/{infoDiagram-HS3SLOUP-OYrX6uO3.js → infoDiagram-HS3SLOUP-CtfUf0g_.js} +9 -9
  40. package/dist/{kanban-definition-3W4ZIXB7-DHEAKdZt.js → kanban-definition-3W4ZIXB7-C5FK4v7x.js} +3 -3
  41. package/dist/main.js +264 -130
  42. package/dist/{mermaid-BbhZNQeB.js → mermaid-CcM8GHeT.js} +29 -29
  43. package/dist/{mermaid-parser.core-ntCgyx0x.js → mermaid-parser.core-fZdPSYor.js} +8 -8
  44. package/dist/min-DAIOAwWK.js +102 -0
  45. package/dist/{mindmap-definition-VGOIOE7T-CxEUZZvY.js → mindmap-definition-VGOIOE7T-BvrQf8XZ.js} +5 -5
  46. package/dist/{packet-DYOGHKS2-BhvnpoGi.js → packet-DYOGHKS2-DDx1z7B-.js} +2 -2
  47. package/dist/pick-DfX21dj2.js +18 -0
  48. package/dist/{pie-VRWISCQL-dILuA3iG.js → pie-VRWISCQL-BgRtyDMT.js} +2 -2
  49. package/dist/{pieDiagram-ADFJNKIX-U3LrUqAS.js → pieDiagram-ADFJNKIX-DAhjFwJD.js} +10 -10
  50. package/dist/{process-output-Bekznt_B.js → process-output-H_7QTreh.js} +2133 -2119
  51. package/dist/{radar-ZZBFDIW7-DwFrOJDj.js → radar-ZZBFDIW7-xwh47Yzn.js} +2 -2
  52. package/dist/{requirementDiagram-UZGBJVZJ-D0zpQnKC.js → requirementDiagram-UZGBJVZJ-B3nnp0VG.js} +5 -5
  53. package/dist/{sequenceDiagram-WL72ISMW-D1BJxLjH.js → sequenceDiagram-WL72ISMW-D2mpRRG2.js} +1 -1
  54. package/dist/{stateDiagram-FKZM4ZOC-B1S8jGMn.js → stateDiagram-FKZM4ZOC-QD9Wuca0.js} +8 -8
  55. package/dist/{stateDiagram-v2-4FDKWEC3-BH5ozUbc.js → stateDiagram-v2-4FDKWEC3-DnUhJ525.js} +6 -6
  56. package/dist/{treemap-GDKQZRPO-bx2ngsgN.js → treemap-GDKQZRPO-5ZsmvXgc.js} +2 -2
  57. package/dist/{xychartDiagram-PRI3JC2R-CuAZiqHS.js → xychartDiagram-PRI3JC2R-BMsB7VdF.js} +2 -2
  58. package/package.json +2 -2
  59. package/src/components/data-table/TableBottomBar.tsx +5 -1
  60. package/src/components/data-table/__tests__/filters.test.ts +304 -0
  61. package/src/components/data-table/__tests__/pagination.test.tsx +46 -132
  62. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
  63. package/src/components/data-table/filters.ts +87 -33
  64. package/src/components/data-table/pagination.tsx +189 -76
  65. package/src/components/data-table/types.ts +0 -4
  66. package/src/components/editor/Output.tsx +1 -1
  67. package/src/components/editor/cell/code/cell-editor.tsx +1 -0
  68. package/src/core/codemirror/__tests__/__snapshots__/setup.test.ts.snap +4 -14
  69. package/src/core/codemirror/cells/extensions.ts +0 -4
  70. package/src/core/codemirror/keymaps/keymaps.ts +69 -2
  71. package/src/core/codemirror/language/languages/python.ts +9 -9
  72. package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +8 -1
  73. package/src/core/codemirror/lsp/federated-lsp.ts +2 -2
  74. package/src/core/codemirror/lsp/notebook-lsp.ts +2 -2
  75. package/src/core/codemirror/lsp/utils.ts +21 -6
  76. package/src/plugins/impl/DataTablePlugin.tsx +7 -20
  77. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +4 -4
  78. package/src/plugins/impl/data-frames/schema.ts +41 -9
  79. package/src/plugins/impl/data-frames/utils/operators.ts +2 -0
  80. package/dist/_basePickBy-Sow3pJjS.js +0 -41
  81. package/dist/min-Ds3gG0Ff.js +0 -96
  82. package/dist/range-fJeId9Ri.js +0 -30
  83. /package/dist/{isEmpty-B7FX9wKt.js → isEmpty-D3lf6gH3.js} +0 -0
  84. /package/dist/{memoize-CSTI9eOX.js → memoize-DEvRzlwP.js} +0 -0
@@ -1,8 +1,16 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
3
  import {
4
+ cursorCharLeft,
5
+ cursorCharRight,
6
+ cursorLineDown,
7
+ cursorLineUp,
4
8
  insertNewlineAndIndent,
5
9
  defaultKeymap as originalDefaultKeymap,
10
+ selectCharLeft,
11
+ selectCharRight,
12
+ selectLineDown,
13
+ selectLineUp,
6
14
  toggleBlockComment,
7
15
  toggleComment,
8
16
  } from "@codemirror/commands";
@@ -13,7 +21,7 @@ import {
13
21
  type KeyBinding,
14
22
  keymap,
15
23
  } from "@codemirror/view";
16
- import { getCM, vim } from "@replit/codemirror-vim";
24
+ import { type CodeMirror, getCM, vim } from "@replit/codemirror-vim";
17
25
  import type { KeymapConfig } from "@/core/config/config-schema";
18
26
  import type { HotkeyProvider } from "@/core/hotkeys/hotkeys";
19
27
  import { logNever } from "@/utils/assertNever";
@@ -62,6 +70,12 @@ export function keymapBundle(
62
70
  },
63
71
  ),
64
72
  ),
73
+ // Arrow keys: use CodeMirror's cursor movement except in vim visual
74
+ // mode, where vim must handle them to maintain selection.
75
+ // The original cursorLineUp/Down bindings from the default keymap are
76
+ // filtered out (see defaultVimKeymap) because their preventDefault
77
+ // flag blocks vim's handler even when their run function returns false.
78
+ keymap.of(vimVisualModeArrowKeyBindings()),
65
79
  // Base vim mode
66
80
  vim({ status: false }),
67
81
  // Custom vim keymaps for cell navigation
@@ -101,12 +115,22 @@ const overrideKeymap = (keymap: HotkeyProvider): readonly KeyBinding[] => {
101
115
  };
102
116
 
103
117
  const defaultVimKeymap = once(() => {
104
- const toRemove = new Set(["Enter", "Ctrl-v"]);
118
+ const toRemove = new Set([
119
+ "Enter",
120
+ "Ctrl-v",
121
+ "ArrowUp",
122
+ "ArrowDown",
123
+ "ArrowLeft",
124
+ "ArrowRight",
125
+ ]);
105
126
  // Remove conflicting keys from the keymap
106
127
  // Enter (<CR>) adds a new line
107
128
  // - it should just go to the next line
108
129
  // Ctrl-v goes to the bottom of the cell
109
130
  // - should enter blockwise visual mode
131
+ // ArrowUp/ArrowDown (cursorLineUp/Down) always handle the event and have
132
+ // preventDefault, which blocks vim's handler from processing arrow keys.
133
+ // Replaced with visual-mode-aware wrappers in keymapBundle.
110
134
  return defaultKeymap().filter(
111
135
  (k) => !toRemove.has(k.key || k.mac || k.linux || k.win || ""),
112
136
  );
@@ -155,6 +179,49 @@ function doubleCharacterListener(
155
179
  ]);
156
180
  }
157
181
 
182
+ function isInVimVisualMode(cm: CodeMirror | undefined | null): boolean {
183
+ return cm?.state.vim?.visualMode === true;
184
+ }
185
+
186
+ /**
187
+ * In vim visual mode, arrow keys must be handled by vim to maintain selection.
188
+ * Wrap each arrow key's run and shift so they defer to vim in visual mode,
189
+ * but use CodeMirror's cursor commands in all other modes.
190
+ */
191
+ function vimVisualModeArrowKeyBindings(): KeyBinding[] {
192
+ const wrap =
193
+ (cmd: Command): Command =>
194
+ (view) => {
195
+ if (isInVimVisualMode(getCM(view))) {
196
+ return false;
197
+ }
198
+ return cmd(view);
199
+ };
200
+
201
+ return [
202
+ {
203
+ key: "ArrowDown",
204
+ run: wrap(cursorLineDown),
205
+ shift: wrap(selectLineDown),
206
+ },
207
+ {
208
+ key: "ArrowUp",
209
+ run: wrap(cursorLineUp),
210
+ shift: wrap(selectLineUp),
211
+ },
212
+ {
213
+ key: "ArrowLeft",
214
+ run: wrap(cursorCharLeft),
215
+ shift: wrap(selectCharLeft),
216
+ },
217
+ {
218
+ key: "ArrowRight",
219
+ run: wrap(cursorCharRight),
220
+ shift: wrap(selectCharRight),
221
+ },
222
+ ];
223
+ }
224
+
158
225
  export const visibleForTesting = {
159
226
  defaultKeymap,
160
227
  defaultVimKeymap,
@@ -36,7 +36,7 @@ import { FederatedLanguageServerClient } from "../../lsp/federated-lsp";
36
36
  import { NotebookLanguageServerClient } from "../../lsp/notebook-lsp";
37
37
  import { createTransport } from "../../lsp/transports";
38
38
  import { CellDocumentUri, type ILanguageServerClient } from "../../lsp/types";
39
- import { getLSPDocumentRootUri } from "../../lsp/utils";
39
+ import { getLspRootUri, getLspWorkspaceFolders } from "../../lsp/utils";
40
40
  import {
41
41
  clickablePlaceholderExtension,
42
42
  smartPlaceholderExtension,
@@ -54,8 +54,8 @@ const pylspClient = once((lspConfig: LSPConfig) => {
54
54
 
55
55
  const lspClientOpts = {
56
56
  transport,
57
- rootUri: getLSPDocumentRootUri(),
58
- workspaceFolders: [],
57
+ rootUri: getLspRootUri(),
58
+ workspaceFolders: getLspWorkspaceFolders(),
59
59
  };
60
60
  const config = lspConfig?.pylsp;
61
61
 
@@ -161,8 +161,8 @@ const tyLspClient = once((_: LSPConfig) => {
161
161
 
162
162
  const lspClientOpts = {
163
163
  transport,
164
- rootUri: getLSPDocumentRootUri(),
165
- workspaceFolders: [],
164
+ rootUri: getLspRootUri(),
165
+ workspaceFolders: getLspWorkspaceFolders(),
166
166
  };
167
167
 
168
168
  // We wrap the client in a NotebookLanguageServerClient to add some
@@ -192,8 +192,8 @@ const pyreflyClient = once(
192
192
 
193
193
  const lspClientOpts = {
194
194
  transport,
195
- rootUri: getLSPDocumentRootUri(),
196
- workspaceFolders: [],
195
+ rootUri: getLspRootUri(),
196
+ workspaceFolders: getLspWorkspaceFolders(),
197
197
  };
198
198
 
199
199
  // We wrap the client in a NotebookLanguageServerClient to add some
@@ -230,8 +230,8 @@ const pyrightClient = once((_: LSPConfig) => {
230
230
 
231
231
  const lspClientOpts = {
232
232
  transport,
233
- rootUri: getLSPDocumentRootUri(),
234
- workspaceFolders: [],
233
+ rootUri: getLspRootUri(),
234
+ workspaceFolders: getLspWorkspaceFolders(),
235
235
  };
236
236
 
237
237
  // We wrap the client in a NotebookLanguageServerClient to add some
@@ -12,6 +12,7 @@ import { cellId } from "@/__tests__/branded";
12
12
  import type { CellId } from "@/core/cells/ids";
13
13
  import { store } from "@/core/state/jotai";
14
14
  import { topologicalCodesAtom } from "../../copilot/getCodes";
15
+ import { lspWorkspaceAtom } from "@/core/saving/file-state";
15
16
  import { languageAdapterState } from "../../language/extension";
16
17
  import { PythonLanguageAdapter } from "../../language/languages/python";
17
18
  import { languageMetadataField } from "../../language/metadata";
@@ -285,6 +286,12 @@ describe("NotebookLanguageServerClient", () => {
285
286
  },
286
287
  };
287
288
  }
289
+ if (atom === lspWorkspaceAtom) {
290
+ return {
291
+ rootUri: "file:///project",
292
+ documentUri: "file:///project/__marimo_notebook__.py",
293
+ };
294
+ }
288
295
  return undefined;
289
296
  });
290
297
 
@@ -421,7 +428,7 @@ describe("NotebookLanguageServerClient", () => {
421
428
  expect(result).toEqual(mockCompletionResponse);
422
429
  expect(mockClient.textDocumentCompletion).toHaveBeenCalledWith(
423
430
  expect.objectContaining({
424
- textDocument: { uri: "file:///__marimo_notebook__.py" },
431
+ textDocument: { uri: "file:///project/__marimo_notebook__.py" },
425
432
  }),
426
433
  );
427
434
  });
@@ -3,7 +3,7 @@
3
3
  import type * as LSP from "vscode-languageserver-protocol";
4
4
  import { Objects } from "@/utils/objects";
5
5
  import type { ILanguageServerClient } from "./types";
6
- import { getLSPDocument } from "./utils";
6
+ import { getLspDocumentUri } from "./utils";
7
7
 
8
8
  function removeFalseyValues<T extends object>(obj: T): T {
9
9
  return Objects.filter(obj, (value) => value !== false && value !== null) as T;
@@ -20,7 +20,7 @@ export class FederatedLanguageServerClient implements ILanguageServerClient {
20
20
 
21
21
  constructor(clients: ILanguageServerClient[]) {
22
22
  this.clients = clients;
23
- this.documentUri = getLSPDocument();
23
+ this.documentUri = getLspDocumentUri();
24
24
  }
25
25
 
26
26
  onNotification(
@@ -22,7 +22,7 @@ import {
22
22
  type ILanguageServerClient,
23
23
  isClientWithNotify,
24
24
  } from "./types";
25
- import { getLSPDocument } from "./utils";
25
+ import { getLspDocumentUri } from "./utils";
26
26
 
27
27
  /**
28
28
  * Check if a variable name is private (starts with underscore but not dunder).
@@ -189,7 +189,7 @@ export class NotebookLanguageServerClient implements ILanguageServerClient {
189
189
  EditorView | null | undefined
190
190
  > = defaultGetNotebookEditors,
191
191
  ) {
192
- this.documentUri = getLSPDocument();
192
+ this.documentUri = getLspDocumentUri();
193
193
  this.getNotebookEditors = getNotebookEditors;
194
194
  this.initialSettings = initialSettings;
195
195
  this.client = client;
@@ -1,11 +1,26 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- import { getFilenameFromDOM } from "@/core/dom/htmlUtils";
3
- import { Paths } from "@/utils/paths";
2
+ import { lspWorkspaceAtom } from "@/core/saving/file-state";
3
+ import { store } from "@/core/state/jotai";
4
4
 
5
- export function getLSPDocument() {
6
- return `file://${getFilenameFromDOM() ?? "/__marimo_notebook__.py"}`;
5
+ export function getLspRootUri() {
6
+ const lspWorkspace = store.get(lspWorkspaceAtom);
7
+ // The backend provides rootUri for active notebook sessions.
8
+ // For non-notebook pages (home, gallery), lspWorkspace is null,
9
+ // so return a valid file URI fallback.
10
+ return lspWorkspace?.rootUri ?? "file:///";
7
11
  }
8
12
 
9
- export function getLSPDocumentRootUri() {
10
- return `file://${Paths.dirname(getFilenameFromDOM() ?? "/")}`;
13
+ export function getLspWorkspaceFolders() {
14
+ const lspWorkspace = store.get(lspWorkspaceAtom);
15
+ const rootUri = lspWorkspace?.rootUri;
16
+ // Return workspace folders only if rootUri is set; empty array otherwise.
17
+ return rootUri ? [{ uri: rootUri, name: "marimo" }] : [];
18
+ }
19
+
20
+ export function getLspDocumentUri() {
21
+ const lspWorkspace = store.get(lspWorkspaceAtom);
22
+ // The backend provides documentUri for active notebook sessions.
23
+ // For non-notebook pages (home, gallery), lspWorkspace is null,
24
+ // so return a valid file URI fallback.
25
+ return lspWorkspace?.documentUri ?? "file:///__marimo_notebook__.py";
11
26
  }
@@ -28,10 +28,7 @@ import { TablePanel } from "@/components/data-table/charts/charts";
28
28
  import { hasChart } from "@/components/data-table/charts/storage";
29
29
  import { ColumnChartSpecModel } from "@/components/data-table/column-summary/chart-spec-model";
30
30
  import { ColumnChartContext } from "@/components/data-table/column-summary/column-summary";
31
- import {
32
- type ColumnFilterValue,
33
- filterToFilterCondition,
34
- } from "@/components/data-table/filters";
31
+ import { filtersToFilterGroup } from "@/components/data-table/filters";
35
32
  import { usePanelOwnership } from "@/components/data-table/hooks/use-panel-ownership";
36
33
  import { LoadingTable } from "@/components/data-table/loading-table";
37
34
  import {
@@ -86,8 +83,8 @@ import { rpc } from "../core/rpc";
86
83
  import { Banner } from "./common/error-banner";
87
84
  import { Labeled } from "./common/labeled";
88
85
  import {
89
- ConditionSchema,
90
- type ConditionType,
86
+ FilterGroupSchema,
87
+ type FilterGroupType,
91
88
  columnToFieldTypesSchema,
92
89
  } from "./data-frames/schema";
93
90
 
@@ -213,7 +210,7 @@ type DataTableFunctions = {
213
210
  descending: boolean;
214
211
  }[];
215
212
  query?: string;
216
- filters?: ConditionType[];
213
+ filters?: FilterGroupType;
217
214
  page_number: number;
218
215
  page_size: number;
219
216
  max_columns?: number | null;
@@ -312,7 +309,7 @@ export const DataTablePlugin = createPlugin<S>("marimo-table")
312
309
  )
313
310
  .optional(),
314
311
  query: z.string().optional(),
315
- filters: z.array(ConditionSchema).optional(),
312
+ filters: FilterGroupSchema.optional(),
316
313
  page_number: z.number(),
317
314
  page_size: z.number(),
318
315
  max_columns: z.number().nullable().optional(),
@@ -578,12 +575,7 @@ export const LoadingDataTableComponent = memo(
578
575
  query: searchQuery,
579
576
  page_number: paginationState.pageIndex,
580
577
  page_size: paginationState.pageSize,
581
- filters: filters.flatMap((filter) => {
582
- return filterToFilterCondition(
583
- filter.id,
584
- filter.value as ColumnFilterValue,
585
- );
586
- }),
578
+ filters: filtersToFilterGroup(filters),
587
579
  });
588
580
 
589
581
  if (canShowInitialPage) {
@@ -641,12 +633,7 @@ export const LoadingDataTableComponent = memo(
641
633
  page_size: 1,
642
634
  sort: sortArgs,
643
635
  query: searchQuery,
644
- filters: filters.flatMap((filter) => {
645
- return filterToFilterCondition(
646
- filter.id,
647
- filter.value as ColumnFilterValue,
648
- );
649
- }),
636
+ filters: filtersToFilterGroup(filters),
650
637
  // Do not clamp number of columns since we are viewing a single row
651
638
  max_columns: null,
652
639
  });
@@ -29,8 +29,8 @@ import { LoadingDataTableComponent, TableProviders } from "../DataTablePlugin";
29
29
  import type { DataType } from "../vega/vega-loader";
30
30
  import { TransformPanel, type TransformPanelHandle } from "./panel";
31
31
  import {
32
- ConditionSchema,
33
- type ConditionType,
32
+ FilterGroupSchema,
33
+ type FilterGroupType,
34
34
  columnToFieldTypesSchema,
35
35
  type Transformations,
36
36
  } from "./schema";
@@ -75,7 +75,7 @@ type PluginFunctions = {
75
75
  descending: boolean;
76
76
  }[];
77
77
  query?: string;
78
- filters?: ConditionType[];
78
+ filters?: FilterGroupType;
79
79
  page_number: number;
80
80
  page_size: number;
81
81
  }) => Promise<{
@@ -138,7 +138,7 @@ export const DataFramePlugin = createPlugin<S>("marimo-dataframe")
138
138
  )
139
139
  .optional(),
140
140
  query: z.string().optional(),
141
- filters: z.array(ConditionSchema).optional(),
141
+ filters: FilterGroupSchema.optional(),
142
142
  page_number: z.number(),
143
143
  page_size: z.number(),
144
144
  }),
@@ -73,16 +73,36 @@ const SortColumnTransformSchema = z.object({
73
73
  .default("last"),
74
74
  });
75
75
 
76
- export const ConditionSchema = z
76
+ export const FilterConditionSchema = z
77
77
  .object({
78
78
  column_id: column_id,
79
79
  operator: z
80
80
  .enum(Object.keys(ALL_OPERATORS) as [OperatorType, ...OperatorType[]])
81
81
  .describe(FieldOptions.of({ label: " " })),
82
+ type: z.literal("condition").default("condition"),
82
83
  value: z.any().describe(FieldOptions.of({ label: "Value" })),
84
+ negate: z.boolean().default(false),
83
85
  })
84
86
  .describe(FieldOptions.of({ direction: "row", special: "column_filter" }));
85
- export type ConditionType = z.infer<typeof ConditionSchema>;
87
+ export type FilterConditionType = z.infer<typeof FilterConditionSchema>;
88
+
89
+ export interface FilterGroupType {
90
+ type: "group";
91
+ operator: "and" | "or";
92
+ children: (FilterConditionType | FilterGroupType)[];
93
+ negate: boolean;
94
+ }
95
+
96
+ export const FilterGroupSchema: z.ZodType<FilterGroupType> = z.lazy(() =>
97
+ z.object({
98
+ type: z.literal("group").default("group"),
99
+ operator: z.enum(["and", "or"]).default("and"),
100
+ children: z
101
+ .array(z.union([FilterConditionSchema, FilterGroupSchema]))
102
+ .default([]),
103
+ negate: z.boolean().default(false),
104
+ }),
105
+ );
86
106
 
87
107
  const FilterRowsTransformSchema = z.object({
88
108
  type: z.literal("filter_rows"),
@@ -91,17 +111,29 @@ const FilterRowsTransformSchema = z.object({
91
111
  .default("keep_rows")
92
112
  .describe(FieldOptions.of({ special: "radio_group" })),
93
113
  where: z
94
- .array(ConditionSchema)
114
+ .array(FilterConditionSchema)
95
115
  .min(1)
96
116
  .describe(FieldOptions.of({ label: "Value", minLength: 1 }))
97
- .transform((value) => {
98
- return value.filter((condition) => {
117
+ .default(() => [
118
+ {
119
+ column_id: "" as ColumnId,
120
+ operator: "==" as const,
121
+ value: "",
122
+ type: "condition" as const,
123
+ negate: false,
124
+ },
125
+ ])
126
+ .transform((value): FilterGroupType => {
127
+ const validConditions = value.filter((condition) => {
99
128
  return isConditionValueValid(condition.operator, condition.value);
100
129
  });
101
- })
102
- .default(() => [
103
- { column_id: "" as ColumnId, operator: "==" as const, value: "" },
104
- ]),
130
+ return {
131
+ type: "group",
132
+ operator: "and",
133
+ children: validConditions,
134
+ negate: false,
135
+ };
136
+ }),
105
137
  });
106
138
 
107
139
  const GroupByTransformSchema = z
@@ -41,6 +41,7 @@ const createComparisonOperators = (schema: z.ZodType) => ({
41
41
  ">=": [schema],
42
42
  "<": [schema],
43
43
  "<=": [schema],
44
+ between: [z.object({ min: schema, max: schema })],
44
45
  is_null: [],
45
46
  is_not_null: [],
46
47
  });
@@ -59,6 +60,7 @@ export const STRING_OPERATORS = {
59
60
  ends_with: [Schema.string],
60
61
  in: [Schema.stringMultiColumnValues],
61
62
  not_in: [Schema.stringMultiColumnValues],
63
+ is_empty: [],
62
64
  is_null: [],
63
65
  is_not_null: [],
64
66
  };
@@ -1,41 +0,0 @@
1
- import { O as _assignValue_default, j as _isIndex_default, z as isObject_default } from "./isArrayLikeObject-LXbTYiBa.js";
2
- import { c as _castPath_default, o as _baseGet_default, r as _baseFlatten_default, s as _toKey_default } from "./hasIn-DnfJcYpY.js";
3
- import { t as toNumber_default } from "./toNumber-55tjPCWr.js";
4
- var INFINITY = Infinity, MAX_INTEGER = 17976931348623157e292;
5
- function toFinite(e) {
6
- return e ? (e = toNumber_default(e), e === INFINITY || e === -INFINITY ? (e < 0 ? -1 : 1) * MAX_INTEGER : e === e ? e : 0) : e === 0 ? e : 0;
7
- }
8
- var toFinite_default = toFinite;
9
- function flatten(e) {
10
- return e != null && e.length ? _baseFlatten_default(e, 1) : [];
11
- }
12
- var flatten_default = flatten;
13
- function baseSet(o, s, l, u) {
14
- if (!isObject_default(o)) return o;
15
- s = _castPath_default(s, o);
16
- for (var d = -1, f = s.length, p = f - 1, m = o; m != null && ++d < f; ) {
17
- var h = _toKey_default(s[d]), g = l;
18
- if (h === "__proto__" || h === "constructor" || h === "prototype") return o;
19
- if (d != p) {
20
- var _ = m[h];
21
- g = u ? u(_, h, m) : void 0, g === void 0 && (g = isObject_default(_) ? _ : _isIndex_default(s[d + 1]) ? [] : {});
22
- }
23
- _assignValue_default(m, h, g), m = m[h];
24
- }
25
- return o;
26
- }
27
- var _baseSet_default = baseSet;
28
- function basePickBy(e, i, a) {
29
- for (var s = -1, c = i.length, l = {}; ++s < c; ) {
30
- var u = i[s], d = _baseGet_default(e, u);
31
- a(d, u) && _baseSet_default(l, _castPath_default(u, e), d);
32
- }
33
- return l;
34
- }
35
- var _basePickBy_default = basePickBy;
36
- export {
37
- toFinite_default as i,
38
- _baseSet_default as n,
39
- flatten_default as r,
40
- _basePickBy_default as t
41
- };
@@ -1,96 +0,0 @@
1
- import { B as isArray_default, C as isArrayLike_default, H as _baseGetTag_default, R as identity_default, S as _isIterateeCall_default, T as _baseRest_default, V as isObjectLike_default, f as keysIn_default, k as eq_default } from "./isArrayLikeObject-LXbTYiBa.js";
2
- import { t as isSymbol_default } from "./isSymbol-DCbjQG_U.js";
3
- import { d as _arrayMap_default, n as _hasPath_default } from "./hasIn-DnfJcYpY.js";
4
- import { i as toFinite_default } from "./_basePickBy-Sow3pJjS.js";
5
- import { C as _baseFindIndex_default, b as keys_default, f as _baseIteratee_default, u as _baseEach_default } from "./_baseUniq-C87CckHL.js";
6
- function toInteger(c) {
7
- var P = toFinite_default(c), F = P % 1;
8
- return P === P ? F ? P - F : P : 0;
9
- }
10
- var toInteger_default = toInteger, objectProto = Object.prototype, hasOwnProperty$1 = objectProto.hasOwnProperty, defaults_default = _baseRest_default(function(c, P) {
11
- c = Object(c);
12
- var F = -1, I = P.length, R = I > 2 ? P[2] : void 0;
13
- for (R && _isIterateeCall_default(P[0], P[1], R) && (I = 1); ++F < I; ) for (var z = P[F], H = keysIn_default(z), U = -1, W = H.length; ++U < W; ) {
14
- var G = H[U], K = c[G];
15
- (K === void 0 || eq_default(K, objectProto[G]) && !hasOwnProperty$1.call(c, G)) && (c[G] = z[G]);
16
- }
17
- return c;
18
- });
19
- function last(c) {
20
- var P = c == null ? 0 : c.length;
21
- return P ? c[P - 1] : void 0;
22
- }
23
- var last_default = last;
24
- function createFind(c) {
25
- return function(F, I, L) {
26
- var R = Object(F);
27
- if (!isArrayLike_default(F)) {
28
- var z = _baseIteratee_default(I, 3);
29
- F = keys_default(F), I = function(c2) {
30
- return z(R[c2], c2, R);
31
- };
32
- }
33
- var B = c(F, I, L);
34
- return B > -1 ? R[z ? F[B] : B] : void 0;
35
- };
36
- }
37
- var _createFind_default = createFind, nativeMax = Math.max;
38
- function findIndex(c, P, F) {
39
- var I = c == null ? 0 : c.length;
40
- if (!I) return -1;
41
- var L = F == null ? 0 : toInteger_default(F);
42
- return L < 0 && (L = nativeMax(I + L, 0)), _baseFindIndex_default(c, _baseIteratee_default(P, 3), L);
43
- }
44
- var find_default = _createFind_default(findIndex);
45
- function baseMap(c, F) {
46
- var I = -1, L = isArrayLike_default(c) ? Array(c.length) : [];
47
- return _baseEach_default(c, function(c2, P, R) {
48
- L[++I] = F(c2, P, R);
49
- }), L;
50
- }
51
- var _baseMap_default = baseMap;
52
- function map(P, F) {
53
- return (isArray_default(P) ? _arrayMap_default : _baseMap_default)(P, _baseIteratee_default(F, 3));
54
- }
55
- var map_default = map, hasOwnProperty = Object.prototype.hasOwnProperty;
56
- function baseHas(c, P) {
57
- return c != null && hasOwnProperty.call(c, P);
58
- }
59
- var _baseHas_default = baseHas;
60
- function has(c, P) {
61
- return c != null && _hasPath_default(c, P, _baseHas_default);
62
- }
63
- var has_default = has, stringTag = "[object String]";
64
- function isString(P) {
65
- return typeof P == "string" || !isArray_default(P) && isObjectLike_default(P) && _baseGetTag_default(P) == stringTag;
66
- }
67
- var isString_default = isString;
68
- function baseLt(c, P) {
69
- return c < P;
70
- }
71
- var _baseLt_default = baseLt;
72
- function baseExtremum(c, P, F) {
73
- for (var I = -1, L = c.length; ++I < L; ) {
74
- var R = c[I], z = P(R);
75
- if (z != null && (B === void 0 ? z === z && !isSymbol_default(z) : F(z, B))) var B = z, V = R;
76
- }
77
- return V;
78
- }
79
- var _baseExtremum_default = baseExtremum;
80
- function min(c) {
81
- return c && c.length ? _baseExtremum_default(c, identity_default, _baseLt_default) : void 0;
82
- }
83
- var min_default = min;
84
- export {
85
- has_default as a,
86
- find_default as c,
87
- toInteger_default as d,
88
- isString_default as i,
89
- last_default as l,
90
- _baseExtremum_default as n,
91
- map_default as o,
92
- _baseLt_default as r,
93
- _baseMap_default as s,
94
- min_default as t,
95
- defaults_default as u
96
- };
@@ -1,30 +0,0 @@
1
- import { E as _overRest_default, M as _setToString_default, S as _isIterateeCall_default } from "./isArrayLikeObject-LXbTYiBa.js";
2
- import { t as hasIn_default } from "./hasIn-DnfJcYpY.js";
3
- import { i as toFinite_default, r as flatten_default, t as _basePickBy_default } from "./_basePickBy-Sow3pJjS.js";
4
- function flatRest(p) {
5
- return _setToString_default(_overRest_default(p, void 0, flatten_default), p + "");
6
- }
7
- var _flatRest_default = flatRest;
8
- function basePick(e, f) {
9
- return _basePickBy_default(e, f, function(f2, p) {
10
- return hasIn_default(e, p);
11
- });
12
- }
13
- var _basePick_default = basePick, pick_default = _flatRest_default(function(e, f) {
14
- return e == null ? {} : _basePick_default(e, f);
15
- }), nativeCeil = Math.ceil, nativeMax = Math.max;
16
- function baseRange(e, f, p, m) {
17
- for (var h = -1, g = nativeMax(nativeCeil((f - e) / (p || 1)), 0), _ = Array(g); g--; ) _[m ? g : ++h] = e, e += p;
18
- return _;
19
- }
20
- var _baseRange_default = baseRange;
21
- function createRange(e) {
22
- return function(f, m, g) {
23
- return g && typeof g != "number" && _isIterateeCall_default(f, m, g) && (m = g = void 0), f = toFinite_default(f), m === void 0 ? (m = f, f = 0) : m = toFinite_default(m), g = g === void 0 ? f < m ? 1 : -1 : toFinite_default(g), _baseRange_default(f, m, g, e);
24
- };
25
- }
26
- var range_default = createRange();
27
- export {
28
- pick_default as n,
29
- range_default as t
30
- };