@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.
- package/dist/{Combination-BVnmMSzE.js → Combination-B--d1_LV.js} +8 -8
- package/dist/{ConnectedDataExplorerComponent-BzRetIpL.js → ConnectedDataExplorerComponent-CTfvzyMi.js} +19 -19
- package/dist/{any-language-editor-BgjMQ0JO.js → any-language-editor-Bj-3432h.js} +4 -4
- package/dist/{button-CxEhg2E1.js → button-qsiIHncQ.js} +10 -11
- package/dist/{capabilities-x7AvQTfX.js → capabilities-BC3mzKnw.js} +1 -1
- package/dist/{chat-ui-Blhe8Kd8.js → chat-ui-BvK3aDSR.js} +13 -13
- package/dist/{check-Cfbm1K98.js → check-D_YwHEgY.js} +1 -1
- package/dist/{copy-Bb-tO2YP.js → copy-CBo9JcJW.js} +2 -2
- package/dist/{dist-eWNxvDQG.js → dist-D2Rk1j4R.js} +2 -2
- package/dist/{error-banner-CW87Aylu.js → error-banner-DkDzvax3.js} +25 -25
- package/dist/{esm-BjPSZ7Qf.js → esm-C9_jY_wu.js} +4 -4
- package/dist/{glide-data-editor-CSemfq4D.js → glide-data-editor-D0IYL4_F.js} +7 -7
- package/dist/{input-EtKyRcb-.js → input-C5uUN4xL.js} +9 -9
- package/dist/{label-mQKeDCJ8.js → label-DwSVaniz.js} +4 -4
- package/dist/{loader-hvRcVSq5.js → loader-DrMJeyDu.js} +15 -15
- package/dist/main.js +17389 -17351
- package/dist/{mermaid-CjhFZReU.js → mermaid-Bwy7OYzI.js} +5 -5
- package/dist/{process-output-Cy0KEXJh.js → process-output-CT8hHGp6.js} +15 -15
- package/dist/{slides-component-DKg-ohoF.js → slides-component-BsaaAy66.js} +2 -2
- package/dist/{spec-DLNqef4y.js → spec-BLAZSydG.js} +3 -3
- package/dist/style.css +1 -1
- package/dist/{toDate-BEXAEQ0o.js → toDate-BWaG12Pv.js} +3 -3
- package/dist/{tooltip-CYv8qy5F.js → tooltip-DGHTbHl5.js} +3 -3
- package/dist/{types-B7Om6oxp.js → types-Dqw69fPc.js} +2 -2
- package/dist/{useAsyncData-b2IfqSIa.js → useAsyncData-Dqt2tV1E.js} +1 -1
- package/dist/{useDeepCompareMemoize-C7Ut95sA.js → useDeepCompareMemoize-D2PKDkrk.js} +4 -4
- package/dist/{useIframeCapabilities-DHGxPMu5.js → useIframeCapabilities-DlwLttZw.js} +1 -1
- package/dist/{useLifecycle-Q7CzdfPd.js → useLifecycle-CJ_5Z4Mk.js} +3 -3
- package/dist/{useTheme-5rRsavIK.js → useTheme-BIAKDAh6.js} +2 -2
- package/dist/{vega-component-B0Ik4707.js → vega-component-CTOT0vRO.js} +9 -9
- package/package.json +1 -1
- package/src/components/data-table/TableActions.tsx +25 -50
- package/src/components/data-table/column-explorer-panel/column-explorer.tsx +24 -13
- package/src/components/data-table/data-table.tsx +11 -9
- package/src/components/data-table/hooks/use-panel-ownership.ts +15 -5
- package/src/components/data-table/row-viewer-panel/row-viewer.tsx +53 -44
- package/src/components/data-table/table-explorer-panel/table-explorer-panel.tsx +161 -0
- package/src/components/editor/chrome/panels/context-aware-panel/context-aware-panel.tsx +16 -9
- package/src/core/slots/slots.ts +1 -0
- 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
|
|
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="
|
|
99
|
-
<div className="
|
|
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="
|
|
103
|
-
size="
|
|
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={
|
|
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:
|
|
160
|
+
minWidth: 400,
|
|
154
161
|
maxWidth: 1500,
|
|
155
162
|
onResize: () => {
|
|
156
163
|
raf2(() => {
|
package/src/core/slots/slots.ts
CHANGED
|
@@ -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 } =
|
|
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
|
|
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
|
-
{
|
|
1034
|
+
{isAnyPanelOpen && (showRowExplorer || canShowColumnExplorer) && (
|
|
1036
1035
|
<ContextAwarePanelItem>
|
|
1037
|
-
<
|
|
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
|
|
1103
|
-
|
|
1104
|
-
|
|
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
|
/>
|