@marimo-team/islands 0.22.1-dev4 → 0.22.1-dev6
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 +84 -72
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/data-table/TableBottomBar.tsx +6 -1
- package/src/components/data-table/charts/charts.tsx +40 -11
- package/src/components/data-table/data-table.tsx +5 -1
- package/src/components/data-table/loading-table.tsx +4 -1
- package/src/css/app/Cell.css +22 -1
- package/src/css/table.css +17 -0
- package/src/plugins/impl/DataTablePlugin.tsx +1 -0
package/package.json
CHANGED
|
@@ -21,6 +21,7 @@ interface TableBottomBarProps<TData> {
|
|
|
21
21
|
getRowIds?: GetRowIds;
|
|
22
22
|
showPageSizeSelector?: boolean;
|
|
23
23
|
tableLoading?: boolean;
|
|
24
|
+
part?: string;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export const TableBottomBar = <TData,>({
|
|
@@ -32,6 +33,7 @@ export const TableBottomBar = <TData,>({
|
|
|
32
33
|
getRowIds,
|
|
33
34
|
showPageSizeSelector,
|
|
34
35
|
tableLoading,
|
|
36
|
+
part,
|
|
35
37
|
}: TableBottomBarProps<TData>) => {
|
|
36
38
|
const { locale } = useLocale();
|
|
37
39
|
const handleSelectAllRows = (value: boolean) => {
|
|
@@ -143,7 +145,10 @@ export const TableBottomBar = <TData,>({
|
|
|
143
145
|
};
|
|
144
146
|
|
|
145
147
|
return (
|
|
146
|
-
<div
|
|
148
|
+
<div
|
|
149
|
+
part={part}
|
|
150
|
+
className="flex lg:grid lg:grid-cols-[1fr_auto_1fr] items-center shrink-0 pt-1"
|
|
151
|
+
>
|
|
147
152
|
<div className="flex flex-col text-sm text-muted-foreground px-2 shrink-0">
|
|
148
153
|
<div className="flex items-center gap-1">{renderTotal()}</div>
|
|
149
154
|
<CellSelectionStats table={table} className="lg:hidden" />
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
XIcon,
|
|
14
14
|
} from "lucide-react";
|
|
15
15
|
import type { JSX } from "react";
|
|
16
|
-
import React, { useMemo, useState } from "react";
|
|
16
|
+
import React, { useMemo, useRef, useState } from "react";
|
|
17
17
|
import { type UseFormReturn, useForm } from "react-hook-form";
|
|
18
18
|
import useResizeObserver from "use-resize-observer";
|
|
19
19
|
import { PythonIcon } from "@/components/editor/cell/code/icons";
|
|
@@ -61,6 +61,7 @@ export interface TablePanelProps {
|
|
|
61
61
|
totalRows: number | TooManyRows;
|
|
62
62
|
columns: number;
|
|
63
63
|
displayHeader: boolean;
|
|
64
|
+
onCloseChartBuilder?: () => void;
|
|
64
65
|
getDataUrl?: GetDataUrl;
|
|
65
66
|
fieldTypes?: FieldTypesWithExternalType | null;
|
|
66
67
|
}
|
|
@@ -74,12 +75,33 @@ export const TablePanel: React.FC<TablePanelProps> = ({
|
|
|
74
75
|
getDataUrl,
|
|
75
76
|
fieldTypes,
|
|
76
77
|
displayHeader,
|
|
78
|
+
onCloseChartBuilder,
|
|
77
79
|
}) => {
|
|
78
80
|
const [tabsMap, saveTabsMap] = useAtom(tabsStorageAtom);
|
|
79
81
|
const tabs = cellId ? (tabsMap.get(cellId) ?? []) : [];
|
|
80
82
|
|
|
81
|
-
const [tabNum, setTabNum] = useState(0);
|
|
82
83
|
const [selectedTab, setSelectedTab] = useState(DEFAULT_TAB_NAME);
|
|
84
|
+
const [tabCounter, setTabCounter] = useState(tabs.length);
|
|
85
|
+
const prevDisplayHeader = useRef(displayHeader);
|
|
86
|
+
|
|
87
|
+
// Auto-create a default chart tab when chart builder opens with no tabs
|
|
88
|
+
if (
|
|
89
|
+
displayHeader &&
|
|
90
|
+
!prevDisplayHeader.current &&
|
|
91
|
+
tabs.length === 0 &&
|
|
92
|
+
cellId
|
|
93
|
+
) {
|
|
94
|
+
prevDisplayHeader.current = displayHeader;
|
|
95
|
+
const tabName = getChartTabName(0, NEW_CHART_TYPE);
|
|
96
|
+
const newTabs = new Map(tabsMap);
|
|
97
|
+
newTabs.set(cellId, [
|
|
98
|
+
{ tabName, chartType: NEW_CHART_TYPE, config: getChartDefaults() },
|
|
99
|
+
]);
|
|
100
|
+
saveTabsMap(newTabs);
|
|
101
|
+
setTabCounter(1);
|
|
102
|
+
setSelectedTab(tabName);
|
|
103
|
+
}
|
|
104
|
+
prevDisplayHeader.current = displayHeader;
|
|
83
105
|
|
|
84
106
|
if (!displayHeader || (tabs.length === 0 && !displayHeader)) {
|
|
85
107
|
return dataTable;
|
|
@@ -89,7 +111,7 @@ export const TablePanel: React.FC<TablePanelProps> = ({
|
|
|
89
111
|
if (!cellId) {
|
|
90
112
|
return;
|
|
91
113
|
}
|
|
92
|
-
const tabName = getChartTabName(
|
|
114
|
+
const tabName = getChartTabName(tabCounter, NEW_CHART_TYPE);
|
|
93
115
|
|
|
94
116
|
const newTabs = new Map(tabsMap);
|
|
95
117
|
newTabs.set(cellId, [
|
|
@@ -102,7 +124,7 @@ export const TablePanel: React.FC<TablePanelProps> = ({
|
|
|
102
124
|
]);
|
|
103
125
|
|
|
104
126
|
saveTabsMap(newTabs);
|
|
105
|
-
|
|
127
|
+
setTabCounter(tabCounter + 1);
|
|
106
128
|
setSelectedTab(tabName);
|
|
107
129
|
};
|
|
108
130
|
|
|
@@ -110,14 +132,21 @@ export const TablePanel: React.FC<TablePanelProps> = ({
|
|
|
110
132
|
if (!cellId) {
|
|
111
133
|
return;
|
|
112
134
|
}
|
|
135
|
+
const deletedIndex = tabs.findIndex((tab) => tab.tabName === tabName);
|
|
136
|
+
const remaining = tabs.filter((tab) => tab.tabName !== tabName);
|
|
113
137
|
const newTabs = new Map(tabsMap);
|
|
114
|
-
newTabs.set(
|
|
115
|
-
cellId,
|
|
116
|
-
tabs.filter((tab) => tab.tabName !== tabName),
|
|
117
|
-
);
|
|
138
|
+
newTabs.set(cellId, remaining);
|
|
118
139
|
saveTabsMap(newTabs);
|
|
119
|
-
|
|
120
|
-
|
|
140
|
+
|
|
141
|
+
if (remaining.length === 0) {
|
|
142
|
+
onCloseChartBuilder?.();
|
|
143
|
+
} else if (tabName === selectedTab) {
|
|
144
|
+
if (deletedIndex < remaining.length) {
|
|
145
|
+
setSelectedTab(remaining[deletedIndex].tabName);
|
|
146
|
+
} else {
|
|
147
|
+
setSelectedTab(remaining[remaining.length - 1].tabName);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
121
150
|
};
|
|
122
151
|
|
|
123
152
|
const saveTabChart = ({
|
|
@@ -178,7 +207,7 @@ export const TablePanel: React.FC<TablePanelProps> = ({
|
|
|
178
207
|
|
|
179
208
|
return (
|
|
180
209
|
<Tabs value={selectedTab} className="-mt-1">
|
|
181
|
-
<TabsList>
|
|
210
|
+
<TabsList part="table-tabs">
|
|
182
211
|
<TabsTrigger
|
|
183
212
|
className="text-xs"
|
|
184
213
|
value={DEFAULT_TAB_NAME}
|
|
@@ -283,7 +283,10 @@ const DataTableInternal = <TData,>({
|
|
|
283
283
|
<div className={cn(wrapperClassName, "flex flex-col space-y-1")}>
|
|
284
284
|
<FilterPills filters={filters} table={table} />
|
|
285
285
|
<CellSelectionProvider>
|
|
286
|
-
<div
|
|
286
|
+
<div
|
|
287
|
+
part="table-wrapper"
|
|
288
|
+
className={cn(className || "rounded-md border overflow-hidden")}
|
|
289
|
+
>
|
|
287
290
|
<TableTopBar
|
|
288
291
|
enableSearch={enableSearch}
|
|
289
292
|
searchQuery={searchQuery}
|
|
@@ -313,6 +316,7 @@ const DataTableInternal = <TData,>({
|
|
|
313
316
|
</Table>
|
|
314
317
|
</div>
|
|
315
318
|
<TableBottomBar
|
|
319
|
+
part="table-footer"
|
|
316
320
|
totalColumns={totalColumns}
|
|
317
321
|
pagination={pagination}
|
|
318
322
|
selection={selection}
|
|
@@ -24,7 +24,10 @@ export const LoadingTable = ({
|
|
|
24
24
|
|
|
25
25
|
return (
|
|
26
26
|
<div className={cn(wrapperClassName, "flex flex-col space-y-2")}>
|
|
27
|
-
<div
|
|
27
|
+
<div
|
|
28
|
+
part="table-wrapper"
|
|
29
|
+
className={cn(className || "rounded-md border")}
|
|
30
|
+
>
|
|
28
31
|
<Table>
|
|
29
32
|
<TableHeader>
|
|
30
33
|
{Array.from({ length: 1 }).map((_, i) => (
|
package/src/css/app/Cell.css
CHANGED
|
@@ -98,9 +98,30 @@
|
|
|
98
98
|
|
|
99
99
|
/* Special case for particular components */
|
|
100
100
|
|
|
101
|
-
.output-area:has(
|
|
101
|
+
.output-area:has(
|
|
102
|
+
> .output:only-child > marimo-ui-element:only-child > marimo-table
|
|
103
|
+
) {
|
|
104
|
+
padding: 0 0 5px;
|
|
102
105
|
max-height: none;
|
|
103
106
|
overflow: hidden;
|
|
107
|
+
|
|
108
|
+
/* Flush table: remove border and configure edge padding via CSS variable */
|
|
109
|
+
--marimo-table-edge-padding: 0.75rem;
|
|
110
|
+
|
|
111
|
+
marimo-table::part(table-tabs) {
|
|
112
|
+
margin-top: 0.25rem;
|
|
113
|
+
border: none;
|
|
114
|
+
border-radius: 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
marimo-table::part(table-wrapper) {
|
|
118
|
+
border: none;
|
|
119
|
+
border-radius: 0;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
marimo-table::part(table-footer) {
|
|
123
|
+
padding-inline: 0.25rem;
|
|
124
|
+
}
|
|
104
125
|
}
|
|
105
126
|
|
|
106
127
|
& > :first-child {
|
package/src/css/table.css
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
@reference "../css/globals.css";
|
|
2
2
|
|
|
3
|
+
/* Edge padding for flush tables (--marimo-table-edge-padding inherits through shadow DOM) */
|
|
4
|
+
[part="table-wrapper"] th:first-child {
|
|
5
|
+
padding-left: var(--marimo-table-edge-padding, 0.5rem);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
[part="table-wrapper"] th:last-child {
|
|
9
|
+
padding-right: var(--marimo-table-edge-padding, 0.5rem);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
[part="table-wrapper"] td:first-child {
|
|
13
|
+
padding-left: var(--marimo-table-edge-padding, 0.375rem);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
[part="table-wrapper"] td:last-child {
|
|
17
|
+
padding-right: var(--marimo-table-edge-padding, 0.375rem);
|
|
18
|
+
}
|
|
19
|
+
|
|
3
20
|
.markdown table,
|
|
4
21
|
table.dataframe {
|
|
5
22
|
display: block;
|
|
@@ -763,6 +763,7 @@ export const LoadingDataTableComponent = memo(
|
|
|
763
763
|
{props.showChartBuilder ? (
|
|
764
764
|
<TablePanel
|
|
765
765
|
displayHeader={displayHeader}
|
|
766
|
+
onCloseChartBuilder={() => setDisplayHeader(false)}
|
|
766
767
|
data={data?.rows || []}
|
|
767
768
|
columns={props.totalColumns}
|
|
768
769
|
totalRows={props.totalRows}
|