@marimo-team/islands 0.21.2-dev93 → 0.21.2-dev94

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 (40) hide show
  1. package/dist/{Combination-BVnmMSzE.js → Combination-B--d1_LV.js} +8 -8
  2. package/dist/{ConnectedDataExplorerComponent-BzRetIpL.js → ConnectedDataExplorerComponent-CTfvzyMi.js} +19 -19
  3. package/dist/{any-language-editor-BgjMQ0JO.js → any-language-editor-Bj-3432h.js} +4 -4
  4. package/dist/{button-CxEhg2E1.js → button-qsiIHncQ.js} +10 -11
  5. package/dist/{capabilities-x7AvQTfX.js → capabilities-BC3mzKnw.js} +1 -1
  6. package/dist/{chat-ui-Blhe8Kd8.js → chat-ui-BvK3aDSR.js} +13 -13
  7. package/dist/{check-Cfbm1K98.js → check-D_YwHEgY.js} +1 -1
  8. package/dist/{copy-Bb-tO2YP.js → copy-CBo9JcJW.js} +2 -2
  9. package/dist/{dist-eWNxvDQG.js → dist-D2Rk1j4R.js} +2 -2
  10. package/dist/{error-banner-CW87Aylu.js → error-banner-DkDzvax3.js} +25 -25
  11. package/dist/{esm-BjPSZ7Qf.js → esm-C9_jY_wu.js} +4 -4
  12. package/dist/{glide-data-editor-CSemfq4D.js → glide-data-editor-D0IYL4_F.js} +7 -7
  13. package/dist/{input-EtKyRcb-.js → input-C5uUN4xL.js} +9 -9
  14. package/dist/{label-mQKeDCJ8.js → label-DwSVaniz.js} +4 -4
  15. package/dist/{loader-hvRcVSq5.js → loader-DrMJeyDu.js} +15 -15
  16. package/dist/main.js +17389 -17351
  17. package/dist/{mermaid-CjhFZReU.js → mermaid-Bwy7OYzI.js} +5 -5
  18. package/dist/{process-output-Cy0KEXJh.js → process-output-CT8hHGp6.js} +15 -15
  19. package/dist/{slides-component-DKg-ohoF.js → slides-component-BsaaAy66.js} +2 -2
  20. package/dist/{spec-DLNqef4y.js → spec-BLAZSydG.js} +3 -3
  21. package/dist/style.css +1 -1
  22. package/dist/{toDate-BEXAEQ0o.js → toDate-BWaG12Pv.js} +3 -3
  23. package/dist/{tooltip-CYv8qy5F.js → tooltip-DGHTbHl5.js} +3 -3
  24. package/dist/{types-B7Om6oxp.js → types-Dqw69fPc.js} +2 -2
  25. package/dist/{useAsyncData-b2IfqSIa.js → useAsyncData-Dqt2tV1E.js} +1 -1
  26. package/dist/{useDeepCompareMemoize-C7Ut95sA.js → useDeepCompareMemoize-D2PKDkrk.js} +4 -4
  27. package/dist/{useIframeCapabilities-DHGxPMu5.js → useIframeCapabilities-DlwLttZw.js} +1 -1
  28. package/dist/{useLifecycle-Q7CzdfPd.js → useLifecycle-CJ_5Z4Mk.js} +3 -3
  29. package/dist/{useTheme-5rRsavIK.js → useTheme-BIAKDAh6.js} +2 -2
  30. package/dist/{vega-component-B0Ik4707.js → vega-component-CTOT0vRO.js} +9 -9
  31. package/package.json +1 -1
  32. package/src/components/data-table/TableActions.tsx +25 -50
  33. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +24 -13
  34. package/src/components/data-table/data-table.tsx +11 -9
  35. package/src/components/data-table/hooks/use-panel-ownership.ts +15 -5
  36. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +53 -44
  37. package/src/components/data-table/table-explorer-panel/table-explorer-panel.tsx +161 -0
  38. package/src/components/editor/chrome/panels/context-aware-panel/context-aware-panel.tsx +16 -9
  39. package/src/core/slots/slots.ts +1 -0
  40. package/src/plugins/impl/DataTablePlugin.tsx +19 -22
@@ -0,0 +1,161 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { Fill } from "@marimo-team/react-slotz";
4
+ import type { OnChangeFn, RowSelectionState } from "@tanstack/react-table";
5
+ import type React from "react";
6
+ import { Button } from "@/components/ui/button";
7
+ import { Tabs, TabsContent } from "@/components/ui/tabs";
8
+ import { SlotNames } from "@/core/slots/slots";
9
+ import type {
10
+ GetRowResult,
11
+ PreviewColumn,
12
+ } from "@/plugins/impl/DataTablePlugin";
13
+ import { cn } from "@/utils/cn";
14
+ import {
15
+ PANEL_TYPES,
16
+ type PanelType,
17
+ } from "../../editor/chrome/panels/context-aware-panel/context-aware-panel";
18
+ import { ColumnExplorerPanel } from "../column-explorer-panel/column-explorer";
19
+ import { RowViewerPanel } from "../row-viewer-panel/row-viewer";
20
+ import type { FieldTypesWithExternalType, TooManyRows } from "../types";
21
+
22
+ export interface TableExplorerPanelProps {
23
+ // Row viewer props
24
+ rowIdx: number;
25
+ setRowIdx: (rowIdx: number) => void;
26
+ totalRows: number | TooManyRows;
27
+ fieldTypes: FieldTypesWithExternalType | undefined | null;
28
+ getRow: (rowIdx: number) => Promise<GetRowResult>;
29
+ isSelectable: boolean;
30
+ isRowSelected: boolean;
31
+ handleRowSelectionChange?: OnChangeFn<RowSelectionState>;
32
+ // Column explorer props
33
+ previewColumn?: PreviewColumn;
34
+ totalColumns: number;
35
+ tableId: string;
36
+ // Visibility flags
37
+ showRowExplorer: boolean;
38
+ showColumnExplorer: boolean;
39
+ // Tab state (driven by contextAwarePanelType atom)
40
+ activeTab: PanelType | null;
41
+ onTabChange: (tab: PanelType) => void;
42
+ }
43
+
44
+ const tabTriggerClassName =
45
+ "text-xs uppercase tracking-wide font-semibold cursor-pointer transition-colors";
46
+ const activeClassName = "text-primary";
47
+ const inactiveClassName = "hover:text-foreground";
48
+
49
+ export const TableExplorerPanel: React.FC<TableExplorerPanelProps> = ({
50
+ // Row viewer
51
+ rowIdx,
52
+ setRowIdx,
53
+ totalRows,
54
+ fieldTypes,
55
+ getRow,
56
+ isSelectable,
57
+ isRowSelected,
58
+ handleRowSelectionChange,
59
+ // Column explorer
60
+ previewColumn,
61
+ totalColumns,
62
+ tableId,
63
+ // Visibility
64
+ showRowExplorer,
65
+ showColumnExplorer,
66
+ // Tab state
67
+ activeTab,
68
+ onTabChange,
69
+ }) => {
70
+ const showTabs = showRowExplorer && showColumnExplorer;
71
+
72
+ const rowViewer = (
73
+ <RowViewerPanel
74
+ rowIdx={rowIdx}
75
+ setRowIdx={setRowIdx}
76
+ totalRows={totalRows}
77
+ fieldTypes={fieldTypes}
78
+ getRow={getRow}
79
+ isSelectable={isSelectable}
80
+ isRowSelected={isRowSelected}
81
+ handleRowSelectionChange={handleRowSelectionChange}
82
+ />
83
+ );
84
+
85
+ const columnExplorer = previewColumn && (
86
+ <ColumnExplorerPanel
87
+ previewColumn={previewColumn}
88
+ fieldTypes={fieldTypes}
89
+ totalRows={totalRows}
90
+ totalColumns={totalColumns}
91
+ tableId={tableId}
92
+ />
93
+ );
94
+
95
+ // If only one panel is visible, don't show tabs
96
+ if (!showTabs) {
97
+ if (showRowExplorer) {
98
+ return rowViewer;
99
+ }
100
+ if (showColumnExplorer) {
101
+ return columnExplorer;
102
+ }
103
+ return null;
104
+ }
105
+
106
+ // Resolve active tab — fall back to first available
107
+ const resolvedTab = activeTab ?? PANEL_TYPES.ROW_VIEWER;
108
+
109
+ return (
110
+ <Tabs
111
+ value={resolvedTab}
112
+ onValueChange={(value) => onTabChange(value as PanelType)}
113
+ className="h-full flex flex-col min-w-[350px]"
114
+ >
115
+ <Fill name={SlotNames.CONTEXT_AWARE_PANEL_HEADER}>
116
+ <div className="flex items-center gap-1">
117
+ <Button
118
+ variant="text"
119
+ size="xs"
120
+ onClick={() => onTabChange(PANEL_TYPES.ROW_VIEWER)}
121
+ className={cn(
122
+ tabTriggerClassName,
123
+ resolvedTab === PANEL_TYPES.ROW_VIEWER
124
+ ? activeClassName
125
+ : inactiveClassName,
126
+ )}
127
+ >
128
+ Rows
129
+ </Button>
130
+ <span className="text-muted-foreground text-xs">|</span>
131
+ <Button
132
+ variant="text"
133
+ size="xs"
134
+ onClick={() => onTabChange(PANEL_TYPES.COLUMN_EXPLORER)}
135
+ className={cn(
136
+ tabTriggerClassName,
137
+ resolvedTab === PANEL_TYPES.COLUMN_EXPLORER
138
+ ? activeClassName
139
+ : inactiveClassName,
140
+ )}
141
+ >
142
+ Explorer
143
+ </Button>
144
+ </div>
145
+ </Fill>
146
+
147
+ <TabsContent
148
+ value={PANEL_TYPES.ROW_VIEWER}
149
+ className="flex-1 overflow-auto"
150
+ >
151
+ {rowViewer}
152
+ </TabsContent>
153
+ <TabsContent
154
+ value={PANEL_TYPES.COLUMN_EXPLORER}
155
+ className="flex-1 overflow-auto"
156
+ >
157
+ {columnExplorer}
158
+ </TabsContent>
159
+ </Tabs>
160
+ );
161
+ };
@@ -21,7 +21,12 @@ import {
21
21
  isPinnedAtom,
22
22
  } from "./atoms";
23
23
 
24
- export type PanelType = "row-viewer" | "column-explorer";
24
+ export const PANEL_TYPES = {
25
+ ROW_VIEWER: "row-viewer",
26
+ COLUMN_EXPLORER: "column-explorer",
27
+ } as const;
28
+
29
+ export type PanelType = (typeof PANEL_TYPES)[keyof typeof PANEL_TYPES];
25
30
 
26
31
  export const ContextAwarePanel: React.FC = () => {
27
32
  const [owner, setOwner] = useAtom(contextAwarePanelOwner);
@@ -51,7 +56,7 @@ export const ContextAwarePanel: React.FC = () => {
51
56
  aria-label={isPinned ? "Unpin panel" : "Pin panel"}
52
57
  >
53
58
  {isPinned ? (
54
- <PinIcon className="w-4 h-4" />
59
+ <PinIcon className="w-4 h-4 text-primary" />
55
60
  ) : (
56
61
  <PinOffIcon className="w-4 h-4" />
57
62
  )}
@@ -95,16 +100,18 @@ export const ContextAwarePanel: React.FC = () => {
95
100
 
96
101
  const renderBody = () => {
97
102
  return (
98
- <div className="mt-2 pb-7 mb-4 h-full overflow-auto">
99
- <div className="flex flex-row justify-between items-center mx-2">
103
+ <div className="pb-7 mb-4 h-full overflow-auto">
104
+ <div className="p-3 border-b flex justify-between items-center">
100
105
  {renderModeToggle()}
106
+ <Slot name={SlotNames.CONTEXT_AWARE_PANEL_HEADER} />
101
107
  <Button
102
- variant="linkDestructive"
103
- size="icon"
108
+ variant="text"
109
+ size="xs"
110
+ className="m-0"
104
111
  onClick={closePanel}
105
112
  aria-label="Close selection panel"
106
113
  >
107
- <XIcon className="w-4 h-4" />
114
+ <XIcon className="w-4 h-4 hover:text-destructive" />
108
115
  </Button>
109
116
  </div>
110
117
 
@@ -126,7 +133,7 @@ export const ContextAwarePanel: React.FC = () => {
126
133
  onDragging={handleDragging}
127
134
  className="resize-handle border-border z-20 print:hidden border-l"
128
135
  />
129
- <Panel defaultSize={20} minSize={15} maxSize={80}>
136
+ <Panel defaultSize={25} minSize={25} maxSize={80}>
130
137
  {renderBody()}
131
138
  </Panel>
132
139
  </>
@@ -150,7 +157,7 @@ interface ResizableComponentProps {
150
157
  const ResizableComponent = ({ children }: ResizableComponentProps) => {
151
158
  const { resizableDivRef, handleRefs, style } = useResizeHandle({
152
159
  startingWidth: 400,
153
- minWidth: 300,
160
+ minWidth: 400,
154
161
  maxWidth: 1500,
155
162
  onResize: () => {
156
163
  raf2(() => {
@@ -6,4 +6,5 @@ export const slotsController = new SlotzController();
6
6
  export const SlotNames = {
7
7
  SIDEBAR: "sidebar",
8
8
  CONTEXT_AWARE_PANEL: "context-aware-panel",
9
+ CONTEXT_AWARE_PANEL_HEADER: "context-aware-panel-header",
9
10
  };
@@ -26,7 +26,6 @@ import type { CellSelectionState } from "@/components/data-table/cell-selection/
26
26
  import type { CellStyleState } from "@/components/data-table/cell-styling/types";
27
27
  import { TablePanel } from "@/components/data-table/charts/charts";
28
28
  import { hasChart } from "@/components/data-table/charts/storage";
29
- import { ColumnExplorerPanel } from "@/components/data-table/column-explorer-panel/column-explorer";
30
29
  import { ColumnChartSpecModel } from "@/components/data-table/column-summary/chart-spec-model";
31
30
  import { ColumnChartContext } from "@/components/data-table/column-summary/column-summary";
32
31
  import {
@@ -35,11 +34,11 @@ import {
35
34
  } from "@/components/data-table/filters";
36
35
  import { usePanelOwnership } from "@/components/data-table/hooks/use-panel-ownership";
37
36
  import { LoadingTable } from "@/components/data-table/loading-table";
38
- import { RowViewerPanel } from "@/components/data-table/row-viewer-panel/row-viewer";
39
37
  import {
40
38
  type DownloadAsArgs,
41
39
  DownloadAsSchema,
42
40
  } from "@/components/data-table/schemas";
41
+ import { TableExplorerPanel } from "@/components/data-table/table-explorer-panel/table-explorer-panel";
43
42
  import {
44
43
  type BinValues,
45
44
  type ColumnHeaderStats,
@@ -839,7 +838,8 @@ const DataTableComponent = ({
839
838
  }): JSX.Element => {
840
839
  const id = useId();
841
840
  const [viewedRowIdx, setViewedRowIdx] = useState(0);
842
- const { isPanelOpen, togglePanel } = usePanelOwnership(id, cellId);
841
+ const { isPanelOpen, isAnyPanelOpen, togglePanel, panelType, setPanelType } =
842
+ usePanelOwnership(id, cellId);
843
843
 
844
844
  const chartSpecModel = useMemo(() => {
845
845
  if (!columnSummaries) {
@@ -1002,8 +1002,7 @@ const DataTableComponent = ({
1002
1002
  );
1003
1003
 
1004
1004
  const isSelectable = selection === "multi" || selection === "single";
1005
- const showColExplorer =
1006
- showColumnExplorer && preview_column && isPanelOpen("column-explorer");
1005
+ const canShowColumnExplorer = showColumnExplorer && !!preview_column;
1007
1006
 
1008
1007
  const isInVscode = isInVscodeExtension();
1009
1008
 
@@ -1032,28 +1031,24 @@ const DataTableComponent = ({
1032
1031
  </Banner>
1033
1032
  )}
1034
1033
 
1035
- {isPanelOpen("row-viewer") && (
1034
+ {isAnyPanelOpen && (showRowExplorer || canShowColumnExplorer) && (
1036
1035
  <ContextAwarePanelItem>
1037
- <RowViewerPanel
1038
- getRow={getRow}
1039
- fieldTypes={memoizedUnclampedFieldTypes}
1040
- totalRows={totalRows}
1036
+ <TableExplorerPanel
1041
1037
  rowIdx={viewedRowIdx}
1042
1038
  setRowIdx={setViewedRow}
1039
+ totalRows={totalRows}
1040
+ fieldTypes={memoizedUnclampedFieldTypes}
1041
+ getRow={getRow}
1043
1042
  isSelectable={isSelectable}
1044
- isRowSelected={rowSelection[viewedRowIdx]}
1043
+ isRowSelected={Boolean(rowSelection[viewedRowIdx])}
1045
1044
  handleRowSelectionChange={handleRowSelectionChange}
1046
- />
1047
- </ContextAwarePanelItem>
1048
- )}
1049
- {showColExplorer && (
1050
- <ContextAwarePanelItem>
1051
- <ColumnExplorerPanel
1052
1045
  previewColumn={preview_column}
1053
- fieldTypes={memoizedUnclampedFieldTypes}
1054
- totalRows={totalRows}
1055
1046
  totalColumns={totalColumns}
1056
1047
  tableId={id}
1048
+ showRowExplorer={showRowExplorer && !isInVscode}
1049
+ showColumnExplorer={canShowColumnExplorer && !isInVscode}
1050
+ activeTab={panelType}
1051
+ onTabChange={setPanelType}
1057
1052
  />
1058
1053
  </ContextAwarePanelItem>
1059
1054
  )}
@@ -1099,11 +1094,13 @@ const DataTableComponent = ({
1099
1094
  showChartBuilder={showChartBuilder}
1100
1095
  showPageSizeSelector={showPageSizeSelector}
1101
1096
  // Hidden in VSCode (for now) because we don't have a panel to show
1102
- // the column/row explorer.
1103
- showColumnExplorer={showColumnExplorer && !isInVscode}
1104
- showRowExplorer={showRowExplorer && !isInVscode}
1097
+ // the table explorer.
1098
+ showTableExplorer={
1099
+ (showRowExplorer || canShowColumnExplorer) && !isInVscode
1100
+ }
1105
1101
  togglePanel={togglePanel}
1106
1102
  isPanelOpen={isPanelOpen}
1103
+ isAnyPanelOpen={isAnyPanelOpen}
1107
1104
  viewedRowIdx={viewedRowIdx}
1108
1105
  onViewedRowChange={(rowIdx) => setViewedRowIdx(rowIdx)}
1109
1106
  />