@hexclave/dashboard-ui-components 1.0.29 → 1.0.32
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/components/button.d.ts +2 -2
- package/dist/components/chart-legend.d.ts +1 -1
- package/dist/components/data-grid/data-grid-export-dialog.d.ts +23 -0
- package/dist/components/data-grid/data-grid-export-dialog.d.ts.map +1 -0
- package/dist/components/data-grid/data-grid-export-dialog.js +406 -0
- package/dist/components/data-grid/data-grid-export-dialog.js.map +1 -0
- package/dist/components/data-grid/data-grid.d.ts.map +1 -1
- package/dist/components/data-grid/data-grid.js +14 -14
- package/dist/components/data-grid/data-grid.js.map +1 -1
- package/dist/components/data-grid/index.d.ts +2 -2
- package/dist/components/data-grid/types.d.ts +31 -2
- package/dist/components/data-grid/types.d.ts.map +1 -1
- package/dist/dashboard-ui-components.global.js +904 -535
- package/dist/dashboard-ui-components.global.js.map +4 -4
- package/dist/esm/components/button.d.ts +2 -2
- package/dist/esm/components/chart-legend.d.ts +1 -1
- package/dist/esm/components/data-grid/data-grid-export-dialog.d.ts +23 -0
- package/dist/esm/components/data-grid/data-grid-export-dialog.d.ts.map +1 -0
- package/dist/esm/components/data-grid/data-grid-export-dialog.js +403 -0
- package/dist/esm/components/data-grid/data-grid-export-dialog.js.map +1 -0
- package/dist/esm/components/data-grid/data-grid.d.ts.map +1 -1
- package/dist/esm/components/data-grid/data-grid.js +16 -16
- package/dist/esm/components/data-grid/data-grid.js.map +1 -1
- package/dist/esm/components/data-grid/index.d.ts +2 -2
- package/dist/esm/components/data-grid/types.d.ts +31 -2
- package/dist/esm/components/data-grid/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/package.json +3 -3
- package/src/components/data-grid/data-grid-export-dialog.tsx +479 -0
- package/src/components/data-grid/data-grid.tsx +192 -193
- package/src/components/data-grid/index.ts +5 -0
- package/src/components/data-grid/types.ts +35 -0
|
@@ -37,8 +37,9 @@ import React, {
|
|
|
37
37
|
|
|
38
38
|
import { DesignSkeleton } from "../skeleton";
|
|
39
39
|
import { DEFAULT_COL_WIDTH, clampColumnWidth, getEffectiveMaxWidth, getEffectiveMinWidth } from "./data-grid-sizing";
|
|
40
|
+
import { DataGridExportDialog } from "./data-grid-export-dialog";
|
|
40
41
|
import { DataGridToolbar } from "./data-grid-toolbar";
|
|
41
|
-
import {
|
|
42
|
+
import { formatGridDate, resolveColumnValue } from "./state";
|
|
42
43
|
import { resolveDataGridStrings } from "./strings";
|
|
43
44
|
import type {
|
|
44
45
|
DataGridCellContext,
|
|
@@ -628,6 +629,7 @@ export function DataGrid<TRow>(props: DataGridProps<TRow>) {
|
|
|
628
629
|
footer,
|
|
629
630
|
footerExtra,
|
|
630
631
|
exportFilename = "export",
|
|
632
|
+
exportOptions,
|
|
631
633
|
strings: stringsOverride,
|
|
632
634
|
className,
|
|
633
635
|
onRowClick,
|
|
@@ -894,24 +896,11 @@ export function DataGrid<TRow>(props: DataGridProps<TRow>) {
|
|
|
894
896
|
);
|
|
895
897
|
}, [rowIds, state.selection.selectedIds, fireSelection]);
|
|
896
898
|
|
|
897
|
-
// ──
|
|
898
|
-
|
|
899
|
-
// paginated mode, or the loaded prefix in infinite mode). To avoid users
|
|
900
|
-
// assuming "Export CSV" means "everything that exists on the server", we
|
|
901
|
-
// confirm with the loaded-row count before downloading. Consumers that
|
|
902
|
-
// want true full-dataset export can override this via a parent toolbar.
|
|
899
|
+
// ── Export ───────────────────────────────────────────────────
|
|
900
|
+
const [exportDialogOpen, setExportDialogOpen] = useState(false);
|
|
903
901
|
const handleExportCsv = useCallback(() => {
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
? ` of ${totalRowCount} total — load more rows first to include them`
|
|
907
|
-
: "";
|
|
908
|
-
const confirmed = window.confirm(
|
|
909
|
-
`Export ${rows.length.toLocaleString()} loaded row${rows.length === 1 ? "" : "s"}${totalSuffix}?`,
|
|
910
|
-
);
|
|
911
|
-
if (!confirmed) return;
|
|
912
|
-
}
|
|
913
|
-
exportToCsv(rows, visibleColumns, exportFilename);
|
|
914
|
-
}, [rows, visibleColumns, exportFilename, totalRowCount]);
|
|
902
|
+
setExportDialogOpen(true);
|
|
903
|
+
}, []);
|
|
915
904
|
|
|
916
905
|
// ── Virtualizer ──────────────────────────────────────────────
|
|
917
906
|
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
|
@@ -1019,81 +1008,90 @@ export function DataGrid<TRow>(props: DataGridProps<TRow>) {
|
|
|
1019
1008
|
const isBounded = fillHeight || maxHeight != null;
|
|
1020
1009
|
|
|
1021
1010
|
return (
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
role="grid"
|
|
1032
|
-
aria-rowcount={totalRowCount ?? rows.length}
|
|
1033
|
-
aria-colcount={visibleColumns.length}
|
|
1034
|
-
>
|
|
1011
|
+
<>
|
|
1012
|
+
<DataGridExportDialog
|
|
1013
|
+
open={exportDialogOpen}
|
|
1014
|
+
onOpenChange={setExportDialogOpen}
|
|
1015
|
+
rows={rows}
|
|
1016
|
+
columns={visibleColumns}
|
|
1017
|
+
exportFilename={exportFilename}
|
|
1018
|
+
exportOptions={exportOptions}
|
|
1019
|
+
/>
|
|
1035
1020
|
<div
|
|
1036
|
-
ref={
|
|
1037
|
-
className=
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
{toolbar
|
|
1043
|
-
? toolbar(toolbarCtx)
|
|
1044
|
-
: (
|
|
1045
|
-
<DataGridToolbar
|
|
1046
|
-
ctx={toolbarCtx}
|
|
1047
|
-
extra={typeof toolbarExtra === "function" ? toolbarExtra(toolbarCtx) : toolbarExtra}
|
|
1048
|
-
/>
|
|
1049
|
-
)}
|
|
1050
|
-
</div>
|
|
1021
|
+
ref={gridRef}
|
|
1022
|
+
className={cn(
|
|
1023
|
+
"isolate flex w-full min-w-0 max-w-full flex-col bg-transparent rounded-[calc(var(--radius)*2)]",
|
|
1024
|
+
fillHeight ? "min-h-0 h-full" : "min-h-0 h-auto",
|
|
1025
|
+
isBounded && "overflow-hidden",
|
|
1026
|
+
className,
|
|
1051
1027
|
)}
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1028
|
+
style={maxHeight != null ? { ...cssVars, maxHeight } : cssVars}
|
|
1029
|
+
role="grid"
|
|
1030
|
+
aria-rowcount={totalRowCount ?? rows.length}
|
|
1031
|
+
aria-colcount={visibleColumns.length}
|
|
1032
|
+
>
|
|
1033
|
+
<div
|
|
1034
|
+
ref={stickyChromeRef}
|
|
1035
|
+
className="sticky z-30 w-full min-w-0 shrink-0 overflow-visible rounded-t-[calc(var(--radius)*2)] bg-white/90 dark:bg-background/60 backdrop-blur-xl"
|
|
1036
|
+
style={{ top: stickyTop ?? (maxHeight != null ? 0 : "var(--data-grid-sticky-top, 0px)") }}
|
|
1037
|
+
>
|
|
1038
|
+
{toolbar !== false && (
|
|
1039
|
+
<div className="relative bg-transparent">
|
|
1040
|
+
{toolbar
|
|
1041
|
+
? toolbar(toolbarCtx)
|
|
1042
|
+
: (
|
|
1043
|
+
<DataGridToolbar
|
|
1044
|
+
ctx={toolbarCtx}
|
|
1045
|
+
extra={typeof toolbarExtra === "function" ? toolbarExtra(toolbarCtx) : toolbarExtra}
|
|
1046
|
+
/>
|
|
1047
|
+
)}
|
|
1057
1048
|
</div>
|
|
1058
1049
|
)}
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1050
|
+
|
|
1051
|
+
<div className="relative">
|
|
1052
|
+
{isRefetching && (
|
|
1053
|
+
<div className="absolute top-0 left-0 right-0 h-0.5 z-30 bg-foreground/[0.04] overflow-hidden">
|
|
1054
|
+
<div className="h-full w-1/3 bg-blue-500/60 rounded-full animate-pulse" />
|
|
1055
|
+
</div>
|
|
1056
|
+
)}
|
|
1063
1057
|
<div
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
role="row"
|
|
1058
|
+
ref={headerScrollRef}
|
|
1059
|
+
className="w-full min-w-0 shrink-0 overflow-hidden border-b border-foreground/[0.06]"
|
|
1067
1060
|
>
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1061
|
+
<div
|
|
1062
|
+
className="flex"
|
|
1063
|
+
style={{ height: headerHeight, minWidth: totalContentWidth }}
|
|
1064
|
+
role="row"
|
|
1065
|
+
>
|
|
1066
|
+
{selectionMode !== "none" && (
|
|
1067
|
+
<div
|
|
1068
|
+
className="flex items-center justify-center border-r border-foreground/[0.04]"
|
|
1069
|
+
style={{ width: 44 }}
|
|
1070
|
+
>
|
|
1071
|
+
{selectionMode === "multiple" && (
|
|
1072
|
+
<SelectionCheckbox
|
|
1073
|
+
checked={allSelected}
|
|
1074
|
+
indeterminate={someSelected}
|
|
1075
|
+
onChange={handleSelectAll}
|
|
1076
|
+
ariaLabel="Select all rows on this page"
|
|
1077
|
+
title="Select all rows on this page"
|
|
1078
|
+
/>
|
|
1079
|
+
)}
|
|
1080
|
+
</div>
|
|
1081
|
+
)}
|
|
1082
|
+
{visibleColumns.map((col) => {
|
|
1083
|
+
const header = headerByColId.get(col.id);
|
|
1084
|
+
if (!header) return null;
|
|
1085
|
+
return <HeaderCell key={col.id} header={header} col={col} resizable={resizable} />;
|
|
1086
|
+
})}
|
|
1087
|
+
</div>
|
|
1089
1088
|
</div>
|
|
1090
1089
|
</div>
|
|
1091
1090
|
</div>
|
|
1092
|
-
</div>
|
|
1093
1091
|
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1092
|
+
<div
|
|
1093
|
+
ref={scrollContainerRef}
|
|
1094
|
+
className={cn(
|
|
1097
1095
|
"relative z-0 w-full min-w-0 overflow-auto bg-transparent",
|
|
1098
1096
|
isBounded ? "min-h-0 flex-1" : "flex-none",
|
|
1099
1097
|
"[&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar]:h-1.5",
|
|
@@ -1101,61 +1099,61 @@ export function DataGrid<TRow>(props: DataGridProps<TRow>) {
|
|
|
1101
1099
|
"[&::-webkit-scrollbar-thumb]:bg-foreground/[0.08] [&::-webkit-scrollbar-thumb]:rounded-full",
|
|
1102
1100
|
"[&::-webkit-scrollbar-thumb]:hover:bg-foreground/[0.15]",
|
|
1103
1101
|
)}
|
|
1104
|
-
|
|
1105
|
-
>
|
|
1106
|
-
<div
|
|
1107
|
-
ref={rowsClipRef}
|
|
1108
|
-
data-data-grid-rows-clip=""
|
|
1109
|
-
className="relative z-0"
|
|
1110
|
-
style={{
|
|
1111
|
-
minWidth: totalContentWidth,
|
|
1112
|
-
clipPath: "inset(var(--data-grid-sticky-overlap, 0px) 0 0 0)",
|
|
1113
|
-
}}
|
|
1102
|
+
onScroll={handleBodyScroll}
|
|
1114
1103
|
>
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1104
|
+
<div
|
|
1105
|
+
ref={rowsClipRef}
|
|
1106
|
+
data-data-grid-rows-clip=""
|
|
1107
|
+
className="relative z-0"
|
|
1108
|
+
style={{
|
|
1109
|
+
minWidth: totalContentWidth,
|
|
1110
|
+
clipPath: "inset(var(--data-grid-sticky-overlap, 0px) 0 0 0)",
|
|
1111
|
+
}}
|
|
1112
|
+
>
|
|
1113
|
+
{isLoading && (
|
|
1114
|
+
<div style={{ minWidth: totalContentWidth }}>
|
|
1115
|
+
{loadingState ?? Array.from({ length: 8 }).map((_, i) => (
|
|
1116
|
+
<SkeletonRow
|
|
1117
|
+
key={i}
|
|
1118
|
+
columns={visibleColumns}
|
|
1119
|
+
height={estimatedRowHeight}
|
|
1120
|
+
showCheckbox={selectionMode !== "none"}
|
|
1121
|
+
/>
|
|
1122
|
+
))}
|
|
1123
|
+
</div>
|
|
1124
|
+
)}
|
|
1125
|
+
|
|
1126
|
+
{!isLoading && rows.length === 0 && (
|
|
1127
|
+
<div
|
|
1128
|
+
className="flex items-center justify-center py-16 text-sm text-muted-foreground"
|
|
1129
|
+
style={{ minWidth: totalContentWidth }}
|
|
1130
|
+
>
|
|
1131
|
+
{emptyState ?? strings.noData}
|
|
1132
|
+
</div>
|
|
1133
|
+
)}
|
|
1134
|
+
|
|
1135
|
+
{!isLoading && rows.length > 0 && (
|
|
1136
|
+
<div
|
|
1137
|
+
style={{
|
|
1138
|
+
height: rowVirtualizer.getTotalSize(),
|
|
1139
|
+
width: "100%",
|
|
1140
|
+
minWidth: totalContentWidth,
|
|
1141
|
+
position: "relative",
|
|
1142
|
+
}}
|
|
1143
|
+
>
|
|
1144
|
+
{rowVirtualizer.getVirtualItems().map((virtualRow: VirtualItem) => {
|
|
1145
|
+
const row = rows[virtualRow.index] ?? throwErr(
|
|
1148
1146
|
`DataGrid: virtualized row index ${virtualRow.index} out of range (rows.length=${rows.length})`,
|
|
1149
1147
|
);
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1148
|
+
const rowId = getRowId(row);
|
|
1149
|
+
const isSelected = state.selection.selectedIds.has(rowId);
|
|
1150
|
+
const isOddRow = virtualRow.index % 2 === 1;
|
|
1151
|
+
return (
|
|
1152
|
+
<div
|
|
1153
|
+
key={rowId}
|
|
1154
|
+
ref={isDynamicRowHeight ? rowVirtualizer.measureElement : undefined}
|
|
1155
|
+
data-index={virtualRow.index}
|
|
1156
|
+
className={cn(
|
|
1159
1157
|
"absolute left-0 w-full flex",
|
|
1160
1158
|
"border-b border-black/[0.03] dark:border-white/[0.03]",
|
|
1161
1159
|
"transition-colors duration-75",
|
|
@@ -1166,66 +1164,67 @@ export function DataGrid<TRow>(props: DataGridProps<TRow>) {
|
|
|
1166
1164
|
: "hover:bg-foreground/[0.025] dark:hover:bg-foreground/[0.04]",
|
|
1167
1165
|
(selectionMode !== "none" || onRowClick) && "cursor-pointer",
|
|
1168
1166
|
)}
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1167
|
+
style={{
|
|
1168
|
+
...(isDynamicRowHeight
|
|
1169
|
+
? { minHeight: estimatedRowHeight }
|
|
1170
|
+
: { height: fixedRowHeight }),
|
|
1171
|
+
transform: `translateY(${virtualRow.start}px)`,
|
|
1172
|
+
}}
|
|
1173
|
+
onClick={(e) => { if (!shouldIgnoreRowClick(e)) handleRowClick(row, rowId, e); }}
|
|
1174
|
+
onDoubleClick={(e) => { if (!shouldIgnoreRowClick(e)) onRowDoubleClick?.(row, rowId, e); }}
|
|
1175
|
+
role="row"
|
|
1176
|
+
aria-rowindex={virtualRow.index + 2}
|
|
1177
|
+
aria-selected={isSelected}
|
|
1178
|
+
data-row-id={rowId}
|
|
1179
|
+
data-state={isSelected ? "selected" : undefined}
|
|
1180
|
+
>
|
|
1181
|
+
{selectionMode !== "none" && (
|
|
1182
|
+
<div
|
|
1183
|
+
className="flex items-center justify-center border-r border-black/[0.04] dark:border-white/[0.04]"
|
|
1184
|
+
style={{ width: 44 }}
|
|
1185
|
+
>
|
|
1186
|
+
<SelectionCheckbox
|
|
1187
|
+
checked={isSelected}
|
|
1188
|
+
onChange={(event) => handleRowClick(row, rowId, event)}
|
|
1189
|
+
ariaLabel={`Select row ${rowId}`}
|
|
1190
|
+
/>
|
|
1191
|
+
</div>
|
|
1192
|
+
)}
|
|
1193
|
+
{visibleColumns.map((col) => (
|
|
1194
|
+
<DataCell
|
|
1195
|
+
key={col.id}
|
|
1196
|
+
col={col}
|
|
1197
|
+
row={row}
|
|
1198
|
+
rowId={rowId}
|
|
1199
|
+
rowIndex={virtualRow.index}
|
|
1200
|
+
isSelected={isSelected}
|
|
1201
|
+
dateDisplay={state.dateDisplay}
|
|
1192
1202
|
/>
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
</div>
|
|
1210
|
-
)}
|
|
1211
|
-
|
|
1212
|
-
{paginationMode === "infinite" && hasMore && !isLoading && (
|
|
1213
|
-
<InfiniteScrollSentinel
|
|
1214
|
-
onIntersect={onLoadMore ?? NOOP}
|
|
1215
|
-
isLoading={isLoadingMore}
|
|
1216
|
-
rootRef={infiniteScrollRootRef}
|
|
1217
|
-
strings={strings}
|
|
1218
|
-
/>
|
|
1219
|
-
)}
|
|
1203
|
+
))}
|
|
1204
|
+
</div>
|
|
1205
|
+
);
|
|
1206
|
+
})}
|
|
1207
|
+
</div>
|
|
1208
|
+
)}
|
|
1209
|
+
|
|
1210
|
+
{paginationMode === "infinite" && hasMore && !isLoading && (
|
|
1211
|
+
<InfiniteScrollSentinel
|
|
1212
|
+
onIntersect={onLoadMore ?? NOOP}
|
|
1213
|
+
isLoading={isLoadingMore}
|
|
1214
|
+
rootRef={infiniteScrollRootRef}
|
|
1215
|
+
strings={strings}
|
|
1216
|
+
/>
|
|
1217
|
+
)}
|
|
1218
|
+
</div>
|
|
1220
1219
|
</div>
|
|
1221
|
-
</div>
|
|
1222
1220
|
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1221
|
+
{footer !== false && (
|
|
1222
|
+
<div className="sticky bottom-0 z-30 shrink-0 overflow-hidden rounded-b-[calc(var(--radius)*2)] bg-white/90 dark:bg-background/60 backdrop-blur-xl">
|
|
1223
|
+
{footer ? footer(footerCtx) : <DefaultFooter ctx={footerCtx} pagination={paginationMode} onChange={onChange} />}
|
|
1224
|
+
{footerExtra && (typeof footerExtra === "function" ? footerExtra(footerCtx) : footerExtra)}
|
|
1225
|
+
</div>
|
|
1226
|
+
)}
|
|
1227
|
+
</div>
|
|
1228
|
+
</>
|
|
1230
1229
|
);
|
|
1231
1230
|
}
|
|
@@ -56,6 +56,11 @@ export type {
|
|
|
56
56
|
DataGridFetchParams,
|
|
57
57
|
DataGridFetchResult,
|
|
58
58
|
DataGridDataSource,
|
|
59
|
+
DataGridExportField,
|
|
60
|
+
DataGridExportFormat,
|
|
61
|
+
DataGridExportOptions,
|
|
62
|
+
DataGridExportRowsOptions,
|
|
63
|
+
DataGridExportScope,
|
|
59
64
|
DataGridCallbacks,
|
|
60
65
|
DataGridProps,
|
|
61
66
|
DataGridToolbarContext,
|
|
@@ -221,6 +221,38 @@ export type DataGridDataSource<TRow> = (
|
|
|
221
221
|
params: DataGridFetchParams,
|
|
222
222
|
) => AsyncGenerator<DataGridFetchResult<TRow>, void, undefined>;
|
|
223
223
|
|
|
224
|
+
// ─── Export ─────────────────────────────────────────────────────────
|
|
225
|
+
export type DataGridExportFormat = "csv" | "json";
|
|
226
|
+
|
|
227
|
+
export type DataGridExportScope = "all" | "filtered";
|
|
228
|
+
|
|
229
|
+
export type DataGridExportField<TRow> = {
|
|
230
|
+
key: string;
|
|
231
|
+
label: string;
|
|
232
|
+
enabled: boolean;
|
|
233
|
+
getValue: (row: TRow) => unknown;
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
export type DataGridExportRowsOptions = {
|
|
237
|
+
scope: DataGridExportScope;
|
|
238
|
+
onProgress: (fetched: number) => void;
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
export type DataGridExportOptions<TRow> = {
|
|
242
|
+
title?: string;
|
|
243
|
+
description?: ReactNode;
|
|
244
|
+
entityName?: string;
|
|
245
|
+
entityNamePlural?: string;
|
|
246
|
+
filenamePrefix?: string;
|
|
247
|
+
fields?: readonly DataGridExportField<TRow>[];
|
|
248
|
+
fetchRows?: (options: DataGridExportRowsOptions) => Promise<readonly TRow[]>;
|
|
249
|
+
emptyExportTitle?: string;
|
|
250
|
+
emptyExportDescription?: string;
|
|
251
|
+
allScopeLabel?: ReactNode;
|
|
252
|
+
filteredScopeLabel?: ReactNode;
|
|
253
|
+
progressSubjectLabel?: string;
|
|
254
|
+
};
|
|
255
|
+
|
|
224
256
|
// ─── Callbacks ───────────────────────────────────────────────────────
|
|
225
257
|
export type DataGridCallbacks<TRow> = {
|
|
226
258
|
onRowClick?: (row: TRow, rowId: RowId, event: React.MouseEvent) => void;
|
|
@@ -334,6 +366,9 @@ export type DataGridProps<TRow> = {
|
|
|
334
366
|
|
|
335
367
|
/** Filename stem for CSV export (without extension). */
|
|
336
368
|
exportFilename?: string;
|
|
369
|
+
/** Full export dialog configuration. If omitted, the dialog exports the
|
|
370
|
+
* currently loaded rows using the grid's visible columns. */
|
|
371
|
+
exportOptions?: DataGridExportOptions<TRow>;
|
|
337
372
|
/** i18n overrides. */
|
|
338
373
|
strings?: Partial<DataGridStrings>;
|
|
339
374
|
|