@jielga/tmdatagrid 2.0.0-beta.13 → 2.0.0-beta.15
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/README.md +5 -212
- package/dist/index.d.ts +967 -610
- package/dist/index.js +2944 -2327
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/docs/anatomy.md +102 -0
- package/docs/cell-selection.md +154 -0
- package/docs/column-layout.md +204 -0
- package/docs/columns.md +262 -0
- package/docs/components.md +303 -0
- package/docs/editing.md +572 -0
- package/docs/editors.md +248 -0
- package/docs/export.md +326 -0
- package/docs/filtering.md +358 -0
- package/docs/getting-started.md +123 -0
- package/docs/grouping.md +165 -0
- package/docs/loading-and-empty.md +92 -0
- package/docs/localization.md +79 -0
- package/docs/menu.md +143 -0
- package/docs/pagination.md +144 -0
- package/docs/persistence.md +111 -0
- package/docs/portfolio-rebalancer.md +94 -0
- package/docs/query-builder.md +175 -0
- package/docs/quick-search.md +83 -0
- package/docs/row-details.md +111 -0
- package/docs/row-interaction.md +148 -0
- package/docs/row-pinning.md +132 -0
- package/docs/row-selection.md +134 -0
- package/docs/row-styling.md +133 -0
- package/docs/scrolling.md +111 -0
- package/docs/server-query.md +246 -0
- package/docs/server-side.md +206 -0
- package/docs/sorting.md +101 -0
- package/docs/styling.md +126 -0
- package/docs/summary-row.md +76 -0
- package/docs/testing.md +309 -0
- package/docs/toolbar.md +161 -0
- package/docs/use-tm-data-grid.md +361 -0
- package/package.json +21 -45
- package/skills/appearance/SKILL.md +31 -15
- package/skills/cell-selection/SKILL.md +44 -41
- package/skills/columns/SKILL.md +33 -32
- package/skills/data/SKILL.md +85 -15
- package/skills/editing/SKILL.md +6 -6
- package/skills/editing/references/common-mistakes.md +12 -12
- package/skills/filtering/SKILL.md +40 -18
- package/skills/getting-started/SKILL.md +5 -5
- package/skills/grouping/SKILL.md +11 -11
- package/skills/options/SKILL.md +5 -5
- package/skills/rows/SKILL.md +15 -15
- package/skills/server-side/SKILL.md +131 -7
- package/skills/testing/SKILL.md +4 -4
- package/src/{tmdatagrid/components → components}/TMDataGrid.tsx +28 -20
- package/src/{tmdatagrid/components → components}/TMDataGridCellEditor.tsx +5 -4
- package/src/{tmdatagrid/components → components}/TMDataGridColumnsPanel.module.css +5 -1
- package/src/{tmdatagrid/components → components}/TMDataGridColumnsPanel.tsx +40 -15
- package/src/components/TMDataGridExportPicker.module.css +77 -0
- package/src/components/TMDataGridExportPicker.tsx +234 -0
- package/src/{tmdatagrid/components → components}/TMDataGridFilterPanel.tsx +22 -6
- package/src/{tmdatagrid/components → components}/TMDataGridFilterPills.tsx +7 -5
- package/src/{tmdatagrid/components → components}/TMDataGridFilterSurface.tsx +8 -3
- package/src/{tmdatagrid/components → components}/TMDataGridFooter.tsx +20 -7
- package/src/{tmdatagrid/components → components}/TMDataGridHeaderCell.tsx +16 -5
- package/src/{tmdatagrid/components → components}/TMDataGridHeaderFilterRow.tsx +2 -4
- package/src/{tmdatagrid/components → components}/TMDataGridMenu.tsx +115 -16
- package/src/{tmdatagrid/components → components}/TMDataGridSelectColumn.tsx +2 -1
- package/src/{tmdatagrid/components → components}/TMDataGridTable.tsx +74 -55
- package/src/{tmdatagrid/components → components}/TMDataGridToolbar.module.css +5 -0
- package/src/{tmdatagrid/components → components}/TMDataGridToolbar.tsx +44 -8
- package/src/{tmdatagrid/components → components}/editors/editorShared.ts +2 -1
- package/src/{tmdatagrid/components → components}/icons.ts +1 -0
- package/src/{tmdatagrid/core → core}/autosize.ts +5 -2
- package/src/{tmdatagrid/core → core}/columnOrdering.ts +33 -14
- package/src/{tmdatagrid/core → core}/columnUtils.ts +44 -5
- package/src/core/dom.ts +74 -0
- package/src/core/export.ts +840 -0
- package/src/{tmdatagrid/core → core}/filterControls.ts +10 -1
- package/src/{tmdatagrid/core → core}/labels.ts +40 -2
- package/src/{tmdatagrid/core → core}/labelsSv.ts +17 -1
- package/src/{tmdatagrid/core → core}/persistence.ts +22 -5
- package/src/{tmdatagrid/core → core}/summary.ts +20 -4
- package/src/{tmdatagrid/index.ts → index.ts} +43 -4
- package/src/{tmdatagrid/useTMDataGrid.tsx → useTMDataGrid.tsx} +100 -45
- package/src/useTMDataGridExport.ts +78 -0
- package/src/tmdatagrid/core/cellExport.ts +0 -320
- /package/src/{tmdatagrid/TMDataGridContext.ts → TMDataGridContext.ts} +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGrid.module.css +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridDetailsColumn.module.css +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridDetailsColumn.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridDraftActions.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridEditColumn.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridEntryRows.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridFilterPanel.module.css +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridFilterPills.module.css +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridFilterSurface.module.css +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridFooter.module.css +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridGroupColumn.module.css +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridGroupColumn.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridHeaderCell.module.css +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridHeaderFilterRow.module.css +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridRowNumberColumn.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridSearch.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridTable.module.css +0 -0
- /package/src/{tmdatagrid/components → components}/editors/TMDataGridBooleanEditor.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/editors/TMDataGridDateEditor.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/editors/TMDataGridMultiSelectEditor.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/editors/TMDataGridNumberEditor.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/editors/TMDataGridSelectEditor.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/editors/TMDataGridStringEditor.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/filters/DgAutocompleteFilter.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/filters/DgDateRangeFilter.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/filters/DgRangeSliderFilter.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/filters/DgTriStateFilter.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/filters/TMDataGridFilterValueInput.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/filters/controlLayout.ts +0 -0
- /package/src/{tmdatagrid/components → components}/filters/filterControlFor.ts +0 -0
- /package/src/{tmdatagrid/components → components}/sticky.module.css +0 -0
- /package/src/{tmdatagrid/components → components}/useHideableColumns.ts +0 -0
- /package/src/{tmdatagrid/core → core}/capabilities.ts +0 -0
- /package/src/{tmdatagrid/core → core}/cellNavigation.ts +0 -0
- /package/src/{tmdatagrid/core → core}/cellRange.ts +0 -0
- /package/src/{tmdatagrid/core → core}/columnOptions.ts +0 -0
- /package/src/{tmdatagrid/core → core}/controlledState.ts +0 -0
- /package/src/{tmdatagrid/core → core}/controlledStateSync.ts +0 -0
- /package/src/{tmdatagrid/core → core}/draftCellContext.ts +0 -0
- /package/src/{tmdatagrid/core → core}/editEngine.ts +0 -0
- /package/src/{tmdatagrid/core → core}/editorFocus.ts +0 -0
- /package/src/{tmdatagrid/core → core}/expanding.ts +0 -0
- /package/src/{tmdatagrid/core → core}/filterOperators.ts +0 -0
- /package/src/{tmdatagrid/core → core}/filterSurface.ts +0 -0
- /package/src/{tmdatagrid/core → core}/grouping.ts +0 -0
- /package/src/{tmdatagrid/core → core}/matchHighlight.ts +0 -0
- /package/src/{tmdatagrid/core → core}/pageReset.ts +0 -0
- /package/src/{tmdatagrid/core → core}/quickSearch.ts +0 -0
- /package/src/{tmdatagrid/core → core}/resizePreview.ts +0 -0
- /package/src/{tmdatagrid/core → core}/rowPinning.ts +0 -0
- /package/src/{tmdatagrid/core → core}/rowSelection.ts +0 -0
- /package/src/{tmdatagrid/core → core}/sizes.ts +0 -0
- /package/src/{tmdatagrid/core → core}/useSettledTableState.ts +0 -0
|
@@ -86,10 +86,19 @@ export type TMDataGridFilterControlComponent =
|
|
|
86
86
|
* declaration of each feeds the filter panel and the cell editor alike.
|
|
87
87
|
*/
|
|
88
88
|
export type TMDataGridColumnFilterOptions = {
|
|
89
|
+
/**
|
|
90
|
+
* The operators this column offers, a subset of the type's own. For a
|
|
91
|
+
* column backed by an endpoint that answers only some of them - `contains`
|
|
92
|
+
* and `equals`, say - so the panel and the header funnel never offer an
|
|
93
|
+
* operator the query cannot express. Kept in the type's order; one the type
|
|
94
|
+
* does not offer is ignored, and a list that leaves nothing falls back to
|
|
95
|
+
* the type's full set.
|
|
96
|
+
*/
|
|
97
|
+
operators?: readonly TMDataGridFilterOperator[];
|
|
89
98
|
/**
|
|
90
99
|
* The operator a fresh filter on this column starts with, instead of the
|
|
91
100
|
* type's default - a salary column can open on `"between"`. Must be one of
|
|
92
|
-
* the
|
|
101
|
+
* the operators the column offers.
|
|
93
102
|
*/
|
|
94
103
|
defaultOperator?: TMDataGridFilterOperator;
|
|
95
104
|
/**
|
|
@@ -148,9 +148,27 @@ export type TMDataGridLabels = {
|
|
|
148
148
|
// Cell selection menu
|
|
149
149
|
cellCount: (count: number) => string;
|
|
150
150
|
copy: string;
|
|
151
|
-
|
|
151
|
+
exportCells: string;
|
|
152
|
+
/** @deprecated Use `exportCells`. Read as its fallback for one beta. */
|
|
153
|
+
exportCsv?: string;
|
|
152
154
|
includeHeaders: string;
|
|
153
155
|
|
|
156
|
+
// Export
|
|
157
|
+
exportAll: string;
|
|
158
|
+
exportSelected: (count: number) => string;
|
|
159
|
+
/** Title of the column picker `columns="custom"` opens; `format` is the file extension in upper case, "CSV". */
|
|
160
|
+
exportPickerTitle: (format: string) => string;
|
|
161
|
+
/** The line under the title; `selected` is the selected row count, or `null` for an export of all rows. */
|
|
162
|
+
exportPickerHint: (selected: number | null) => string;
|
|
163
|
+
exportPickerConfirm: string;
|
|
164
|
+
exportPickerCancel: string;
|
|
165
|
+
/** The select-all row over the picker's list. */
|
|
166
|
+
exportPickerSelectAll: string;
|
|
167
|
+
/** The "3 of 12" count beside it. */
|
|
168
|
+
exportPickerCount: (checked: number, total: number) => string;
|
|
169
|
+
/** Marks a column the grid hides at the moment. */
|
|
170
|
+
exportPickerHidden: string;
|
|
171
|
+
|
|
154
172
|
// Generated checkbox lane
|
|
155
173
|
selectColumnLabel: string;
|
|
156
174
|
selectAllRows: string;
|
|
@@ -274,9 +292,25 @@ export const TMDATAGRID_LABELS_EN: TMDataGridLabels = {
|
|
|
274
292
|
|
|
275
293
|
cellCount: (count) => (count === 1 ? "1 cell" : `${count} cells`),
|
|
276
294
|
copy: "Copy",
|
|
277
|
-
|
|
295
|
+
exportCells: "Export cells",
|
|
278
296
|
includeHeaders: "Include headers",
|
|
279
297
|
|
|
298
|
+
exportAll: "Export all rows",
|
|
299
|
+
exportSelected: (count) =>
|
|
300
|
+
count === 1 ? "Export 1 selected row" : `Export ${count} selected rows`,
|
|
301
|
+
exportPickerTitle: (format) => `Export as ${format}`,
|
|
302
|
+
exportPickerHint: (selected) =>
|
|
303
|
+
selected === null
|
|
304
|
+
? "Select the columns to export"
|
|
305
|
+
: selected === 1
|
|
306
|
+
? "Select the columns to export for the selected row"
|
|
307
|
+
: `Select the columns to export for the ${selected} selected rows`,
|
|
308
|
+
exportPickerConfirm: "Export",
|
|
309
|
+
exportPickerCancel: "Cancel",
|
|
310
|
+
exportPickerSelectAll: "Select all",
|
|
311
|
+
exportPickerCount: (checked, total) => `${checked} of ${total}`,
|
|
312
|
+
exportPickerHidden: "Hidden",
|
|
313
|
+
|
|
280
314
|
selectColumnLabel: "Checkbox selection",
|
|
281
315
|
selectAllRows: "Select all rows",
|
|
282
316
|
selectRow: "Select row",
|
|
@@ -302,6 +336,10 @@ export function mergeLabels(
|
|
|
302
336
|
return {
|
|
303
337
|
...TMDATAGRID_LABELS_EN,
|
|
304
338
|
...override,
|
|
339
|
+
exportCells:
|
|
340
|
+
override.exportCells ??
|
|
341
|
+
override.exportCsv ??
|
|
342
|
+
TMDATAGRID_LABELS_EN.exportCells,
|
|
305
343
|
operators: {
|
|
306
344
|
...TMDATAGRID_LABELS_EN.operators,
|
|
307
345
|
...override.operators,
|
|
@@ -121,9 +121,25 @@ export const TMDATAGRID_LABELS_SV: TMDataGridLabels = {
|
|
|
121
121
|
|
|
122
122
|
cellCount: (count) => (count === 1 ? "1 cell" : `${count} celler`),
|
|
123
123
|
copy: "Kopiera",
|
|
124
|
-
|
|
124
|
+
exportCells: "Exportera celler",
|
|
125
125
|
includeHeaders: "Inkludera rubriker",
|
|
126
126
|
|
|
127
|
+
exportAll: "Exportera alla rader",
|
|
128
|
+
exportSelected: (count) =>
|
|
129
|
+
count === 1 ? "Exportera 1 vald rad" : `Exportera ${count} valda rader`,
|
|
130
|
+
exportPickerTitle: (format) => `Exportera som ${format}`,
|
|
131
|
+
exportPickerHint: (selected) =>
|
|
132
|
+
selected === null
|
|
133
|
+
? "Välj kolumner att exportera"
|
|
134
|
+
: selected === 1
|
|
135
|
+
? "Välj kolumner att exportera för den valda raden"
|
|
136
|
+
: `Välj kolumner att exportera för de ${selected} valda raderna`,
|
|
137
|
+
exportPickerConfirm: "Exportera",
|
|
138
|
+
exportPickerCancel: "Avbryt",
|
|
139
|
+
exportPickerSelectAll: "Markera alla",
|
|
140
|
+
exportPickerCount: (checked, total) => `${checked} av ${total}`,
|
|
141
|
+
exportPickerHidden: "Dold",
|
|
142
|
+
|
|
127
143
|
selectColumnLabel: "Kryssrutemarkering",
|
|
128
144
|
selectAllRows: "Markera alla rader",
|
|
129
145
|
selectRow: "Markera rad",
|
|
@@ -188,12 +188,26 @@ const SLICE_GUARDS: Record<
|
|
|
188
188
|
isRecordOf(value, (entry) => typeof entry === "boolean"),
|
|
189
189
|
columnSizing: (value) => isRecordOf(value, isFiniteNumber),
|
|
190
190
|
columnOrder: (value) => isArrayOf(value, isString),
|
|
191
|
+
// Both the current logical shape and the physical one 1.x wrote.
|
|
191
192
|
columnPinning: (value) =>
|
|
192
|
-
isArrayOf(prop(value, "
|
|
193
|
-
|
|
193
|
+
(isArrayOf(prop(value, "start"), isString) &&
|
|
194
|
+
isArrayOf(prop(value, "end"), isString)) ||
|
|
195
|
+
(isArrayOf(prop(value, "left"), isString) &&
|
|
196
|
+
isArrayOf(prop(value, "right"), isString)),
|
|
194
197
|
grouping: (value) => isArrayOf(value, isString),
|
|
195
198
|
};
|
|
196
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Settings saved by 1.x used TanStack's old physical `columnPinning` keys.
|
|
202
|
+
* Rewrite them once on read, so nothing downstream sees `left` / `right`.
|
|
203
|
+
*/
|
|
204
|
+
function normalizeColumnPinning(value: unknown): unknown {
|
|
205
|
+
const left = prop(value, "left");
|
|
206
|
+
const right = prop(value, "right");
|
|
207
|
+
if (left === undefined || right === undefined) return value;
|
|
208
|
+
return { start: left, end: right };
|
|
209
|
+
}
|
|
210
|
+
|
|
197
211
|
function isValidSlice(slice: keyof GridState, value: unknown): boolean {
|
|
198
212
|
const guard = SLICE_GUARDS[slice as keyof typeof SLICE_GUARDS];
|
|
199
213
|
return guard === undefined || guard(value);
|
|
@@ -219,7 +233,10 @@ function readSlices(
|
|
|
219
233
|
for (const slice of resolved.slices) {
|
|
220
234
|
if (!(slice in record)) continue;
|
|
221
235
|
if (!isValidSlice(slice, record[slice])) continue;
|
|
222
|
-
restored[slice] =
|
|
236
|
+
restored[slice] =
|
|
237
|
+
slice === "columnPinning"
|
|
238
|
+
? normalizeColumnPinning(record[slice])
|
|
239
|
+
: record[slice];
|
|
223
240
|
}
|
|
224
241
|
return restored as Partial<GridState>;
|
|
225
242
|
} catch {
|
|
@@ -323,8 +340,8 @@ function realignToColumns(
|
|
|
323
340
|
}
|
|
324
341
|
if (restored.columnPinning) {
|
|
325
342
|
realigned.columnPinning = {
|
|
326
|
-
|
|
327
|
-
|
|
343
|
+
start: keepIds(restored.columnPinning.start ?? []),
|
|
344
|
+
end: keepIds(restored.columnPinning.end ?? []),
|
|
328
345
|
};
|
|
329
346
|
}
|
|
330
347
|
if (restored.sorting) realigned.sorting = keepEntries(restored.sorting);
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type AggregationContext,
|
|
3
|
+
aggregationFns,
|
|
4
|
+
type RowData,
|
|
5
|
+
} from "@tanstack/react-table";
|
|
2
6
|
import type { TMDataGridRowData } from "../TMDataGridContext";
|
|
3
|
-
import type { TMDataGridTable } from "../useTMDataGrid";
|
|
7
|
+
import type { TMDataGridFeatures, TMDataGridTable } from "../useTMDataGrid";
|
|
4
8
|
|
|
5
9
|
/** The registered aggregation names - the same set `aggregationFn` accepts. */
|
|
6
10
|
export type TMDataGridAggregationName = keyof typeof aggregationFns;
|
|
@@ -33,11 +37,23 @@ export function aggregateColumn<TData extends RowData>({
|
|
|
33
37
|
fn?: TMDataGridAggregationName;
|
|
34
38
|
}): unknown {
|
|
35
39
|
const erased = table as unknown as TMDataGridTable<TMDataGridRowData>;
|
|
40
|
+
const column = erased.getColumn(columnId);
|
|
41
|
+
// A summary for a column the table does not hold has no value.
|
|
42
|
+
if (!column) return undefined;
|
|
36
43
|
// `flatRows`, not `rows`: the filtered model nests under `getSubRows`, and
|
|
37
44
|
// the top-level array would total a tree's roots and drop every child.
|
|
38
45
|
// Grouping does not nest it - the group rows are built from this model, not
|
|
39
46
|
// held in it - so a grouped grid is unaffected either way.
|
|
40
47
|
const rows = erased.getFilteredRowModel().flatRows;
|
|
41
|
-
//
|
|
42
|
-
|
|
48
|
+
// The rows are already every row, so there is nothing below them to select:
|
|
49
|
+
// `maxDepth: 0`, and no `subRows` or `groupingRow` - this is not a group.
|
|
50
|
+
const context: AggregationContext<TMDataGridFeatures, TMDataGridRowData> = {
|
|
51
|
+
column,
|
|
52
|
+
columnId,
|
|
53
|
+
maxDepth: 0,
|
|
54
|
+
getValue: (row) => row.getValue(columnId),
|
|
55
|
+
rows,
|
|
56
|
+
table: erased,
|
|
57
|
+
};
|
|
58
|
+
return aggregationFns[fn].aggregate(context);
|
|
43
59
|
}
|
|
@@ -32,6 +32,10 @@ export {
|
|
|
32
32
|
useTMDataGrid,
|
|
33
33
|
type UseTMDataGridOptions,
|
|
34
34
|
} from "./useTMDataGrid";
|
|
35
|
+
export {
|
|
36
|
+
useTMDataGridExport,
|
|
37
|
+
type TMDataGridExportApi,
|
|
38
|
+
} from "./useTMDataGridExport";
|
|
35
39
|
export {
|
|
36
40
|
TMDataGridFilterPills,
|
|
37
41
|
type TMDataGridFilterPillsProps,
|
|
@@ -42,6 +46,7 @@ export {
|
|
|
42
46
|
} from "./components/TMDataGridSearch";
|
|
43
47
|
export type {
|
|
44
48
|
TMDataGridMenuColumnsProps,
|
|
49
|
+
TMDataGridMenuExportProps,
|
|
45
50
|
TMDataGridMenuProps,
|
|
46
51
|
} from "./components/TMDataGridMenu";
|
|
47
52
|
export {
|
|
@@ -126,6 +131,8 @@ export type {
|
|
|
126
131
|
TMDataGridFilterSurface,
|
|
127
132
|
} from "./core/filterSurface";
|
|
128
133
|
export type { TMDataGridFilterPanelProps } from "./components/TMDataGridFilterPanel";
|
|
134
|
+
export type { TMDataGridColumnsPanelProps } from "./components/TMDataGridColumnsPanel";
|
|
135
|
+
export type { TMDataGridToolbarProps } from "./components/TMDataGridToolbar";
|
|
129
136
|
export { TMDataGridFilterValueInput } from "./components/filters/TMDataGridFilterValueInput";
|
|
130
137
|
export { DgRangeSliderFilter } from "./components/filters/DgRangeSliderFilter";
|
|
131
138
|
export { DgDateRangeFilter } from "./components/filters/DgDateRangeFilter";
|
|
@@ -147,12 +154,14 @@ export { TMDATAGRID_LABELS_SV } from "./core/labelsSv";
|
|
|
147
154
|
export {
|
|
148
155
|
getColumnDefaultOperator,
|
|
149
156
|
getColumnFilterControl,
|
|
157
|
+
getColumnOperators,
|
|
150
158
|
getColumnLabel,
|
|
151
159
|
getColumnType,
|
|
152
160
|
isColumnEditableForRow,
|
|
153
161
|
isColumnReorderable,
|
|
154
162
|
isControlColumn,
|
|
155
163
|
isGeneratedColumn,
|
|
164
|
+
type TMDataGridColumnSearchable,
|
|
156
165
|
} from "./core/columnUtils";
|
|
157
166
|
export { getGroupDataRows } from "./core/grouping";
|
|
158
167
|
export {
|
|
@@ -177,19 +186,49 @@ export {
|
|
|
177
186
|
type TMDataGridRangeBounds,
|
|
178
187
|
} from "./core/cellRange";
|
|
179
188
|
export {
|
|
189
|
+
buildExportData,
|
|
190
|
+
countSelectedExportRows,
|
|
191
|
+
csvExcelFormat,
|
|
192
|
+
csvFormat,
|
|
193
|
+
DEFAULT_EXPORT_OPTIONS,
|
|
194
|
+
downloadFile,
|
|
195
|
+
exportGrid,
|
|
196
|
+
formatExportValue,
|
|
197
|
+
getExportableColumns,
|
|
198
|
+
guardFormula,
|
|
199
|
+
jsonFormat,
|
|
200
|
+
resolveExportOptions,
|
|
201
|
+
toClipboardText,
|
|
202
|
+
tsvFormat,
|
|
203
|
+
writeClipboardText,
|
|
204
|
+
writeExportFile,
|
|
205
|
+
type BuildExportDataArgs,
|
|
206
|
+
type ExportGridArgs,
|
|
207
|
+
type TMDataGridClipboardTextOptions,
|
|
208
|
+
type TMDataGridCsvFormatOptions,
|
|
209
|
+
type TMDataGridExportColumns,
|
|
210
|
+
type TMDataGridExportData,
|
|
211
|
+
type TMDataGridExportFormat,
|
|
212
|
+
type TMDataGridExportOptions,
|
|
213
|
+
type TMDataGridExportPickerRequest,
|
|
214
|
+
type TMDataGridExportRows,
|
|
215
|
+
type TMDataGridExportSettings,
|
|
216
|
+
type TMDataGridExportValueGetter,
|
|
217
|
+
type TMDataGridExportWriteOptions,
|
|
218
|
+
type TMDataGridJsonFormatOptions,
|
|
219
|
+
type TMDataGridTsvFormatOptions,
|
|
220
|
+
// Deprecated, gone in the next beta.
|
|
180
221
|
buildCellMatrix,
|
|
181
222
|
buildGridCellMatrix,
|
|
182
223
|
DEFAULT_CELL_EXPORT_OPTIONS,
|
|
183
224
|
downloadTextFile,
|
|
184
225
|
exportGridToCsv,
|
|
185
|
-
|
|
186
|
-
toClipboardText,
|
|
226
|
+
fromCellExportOptions,
|
|
187
227
|
toExcelCsv,
|
|
188
|
-
writeClipboardText,
|
|
189
228
|
type BuildCellMatrixArgs,
|
|
190
229
|
type TMDataGridCellExportOptions,
|
|
191
230
|
type TMDataGridCellMatrix,
|
|
192
|
-
} from "./core/
|
|
231
|
+
} from "./core/export";
|
|
193
232
|
export {
|
|
194
233
|
areAllRowsExpanded,
|
|
195
234
|
resolveExpandAll,
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
metaHelper,
|
|
25
25
|
type Row,
|
|
26
26
|
type RowData,
|
|
27
|
+
rowAggregationFeature,
|
|
27
28
|
rowExpandingFeature,
|
|
28
29
|
rowPaginationFeature,
|
|
29
30
|
rowPinningFeature,
|
|
@@ -116,6 +117,13 @@ import {
|
|
|
116
117
|
type TMDataGridQueryTable,
|
|
117
118
|
} from "./core/pageReset";
|
|
118
119
|
import type { TMDataGridCellRange } from "./core/cellRange";
|
|
120
|
+
import {
|
|
121
|
+
resolveExportOptions,
|
|
122
|
+
type TMDataGridExportOptions,
|
|
123
|
+
type TMDataGridExportPickerRequest,
|
|
124
|
+
type TMDataGridExportSettings,
|
|
125
|
+
type TMDataGridExportValueGetter,
|
|
126
|
+
} from "./core/export";
|
|
119
127
|
import {
|
|
120
128
|
createSelectColumn,
|
|
121
129
|
SELECT_COLUMN_ID,
|
|
@@ -186,8 +194,8 @@ export type TMDataGridColumnMeta = {
|
|
|
186
194
|
*/
|
|
187
195
|
enableOrdering?: boolean;
|
|
188
196
|
/**
|
|
189
|
-
* How this column filters: the operator a fresh
|
|
190
|
-
* value control the filter panel renders for it.
|
|
197
|
+
* How this column filters: which operators it offers, the operator a fresh
|
|
198
|
+
* filter starts with, and the value control the filter panel renders for it.
|
|
191
199
|
*
|
|
192
200
|
* ```tsx
|
|
193
201
|
* meta: {
|
|
@@ -214,6 +222,25 @@ export type TMDataGridColumnMeta = {
|
|
|
214
222
|
* See {@link TMDataGridColumnEditOptions}.
|
|
215
223
|
*/
|
|
216
224
|
edit?: TMDataGridColumnEditOptions;
|
|
225
|
+
/**
|
|
226
|
+
* `false` leaves the column out of every export and out of Ctrl+C - for a
|
|
227
|
+
* column of buttons, or one whose value means nothing outside the grid.
|
|
228
|
+
* Defaults to `true`.
|
|
229
|
+
*/
|
|
230
|
+
enableExport?: boolean;
|
|
231
|
+
/**
|
|
232
|
+
* The value an export writes for this column, in place of
|
|
233
|
+
* `row.getValue(column.id)`. The export otherwise writes the value, never
|
|
234
|
+
* what the cell renders, so this is where a status code becomes its label
|
|
235
|
+
* or a nested object becomes one field.
|
|
236
|
+
*
|
|
237
|
+
* ```tsx
|
|
238
|
+
* meta: {
|
|
239
|
+
* exportValue: ({ value }) => STATUS_LABELS[value as Status],
|
|
240
|
+
* }
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
243
|
+
exportValue?: TMDataGridExportValueGetter;
|
|
217
244
|
};
|
|
218
245
|
|
|
219
246
|
/** Grid-wide configuration passed through `options.meta`. */
|
|
@@ -246,6 +273,7 @@ export const tmDataGridFeatures = tableFeatures({
|
|
|
246
273
|
columnResizingFeature,
|
|
247
274
|
columnFacetingFeature,
|
|
248
275
|
columnGroupingFeature,
|
|
276
|
+
rowAggregationFeature,
|
|
249
277
|
// Registered for grouping's sake rather than for tree data: the grouped row
|
|
250
278
|
// model builds the parent rows, and this is what flattens the expanded ones
|
|
251
279
|
// back into the flat list the body virtualizes.
|
|
@@ -371,11 +399,21 @@ export type TMDataGridUiState = {
|
|
|
371
399
|
* describe different places.
|
|
372
400
|
*/
|
|
373
401
|
cellRange: TMDataGridCellRange | null;
|
|
402
|
+
/**
|
|
403
|
+
* The export column picker, while it is open: which rows it exports and the
|
|
404
|
+
* options of the item that opened it. `null` while closed. Held here rather
|
|
405
|
+
* than in the menu item, which unmounts with the dropdown the moment it is
|
|
406
|
+
* clicked.
|
|
407
|
+
*/
|
|
408
|
+
exportPicker: TMDataGridExportPickerRequest | null;
|
|
374
409
|
};
|
|
375
410
|
|
|
376
411
|
export type TMDataGridUiActions = {
|
|
377
412
|
openFilterPanel: (columnId?: string | null) => void;
|
|
378
413
|
closeFilterPanel: () => void;
|
|
414
|
+
/** Opens the export column picker for `request`. See `TMDataGrid.Menu.Export`'s `columns="custom"`. */
|
|
415
|
+
openExportPicker: (request: TMDataGridExportPickerRequest) => void;
|
|
416
|
+
closeExportPicker: () => void;
|
|
379
417
|
/**
|
|
380
418
|
* Points at a column's row in the filter panel without opening anything.
|
|
381
419
|
* `openFilterPanel` does this as well as opening; this is the half a panel
|
|
@@ -446,6 +484,12 @@ export type TMDataGridApi<TData extends RowData> = {
|
|
|
446
484
|
* table about which surface is on.
|
|
447
485
|
*/
|
|
448
486
|
filters: TMDataGridFiltersSettings;
|
|
487
|
+
/**
|
|
488
|
+
* How the grid exports, the `exportOptions` option with its defaults filled
|
|
489
|
+
* in. Read by `useTMDataGridExport`, the `TMDataGrid.Menu.Export*` items and
|
|
490
|
+
* the cell-range menu, so every export of the grid agrees on the format.
|
|
491
|
+
*/
|
|
492
|
+
exportOptions: TMDataGridExportSettings;
|
|
449
493
|
/** Every string the chrome renders, `labels` merged over the English defaults. */
|
|
450
494
|
labels: TMDataGridLabels;
|
|
451
495
|
/** The detail renderer, when row details are on. See `renderDetails`. */
|
|
@@ -769,6 +813,20 @@ export type UseTMDataGridOptions<TData extends RowData> = Omit<
|
|
|
769
813
|
* `persist`, this one does not have to be referentially stable.
|
|
770
814
|
*/
|
|
771
815
|
filters?: TMDataGridFiltersOptions;
|
|
816
|
+
/**
|
|
817
|
+
* How the grid exports: the file format, the file name and whether the
|
|
818
|
+
* column labels go in as the first row. Defaults to `csvExcelFormat()`,
|
|
819
|
+
* `"export"` and `true`. See {@link TMDataGridExportOptions}.
|
|
820
|
+
*
|
|
821
|
+
* ```tsx
|
|
822
|
+
* useTMDataGrid({ data, columns, exportOptions: { format: csvFormat(), fileName: "employees" } });
|
|
823
|
+
* ```
|
|
824
|
+
*
|
|
825
|
+
* Read field by field like `filters`, so a literal is fine. A `format`
|
|
826
|
+
* built inline is rebuilt every render, which costs nothing but a small
|
|
827
|
+
* object; keep it at module scope when that bothers you.
|
|
828
|
+
*/
|
|
829
|
+
exportOptions?: TMDataGridExportOptions;
|
|
772
830
|
/**
|
|
773
831
|
* How the quick search (`TMDataGrid.Search`) matches. `"fuzzy"` - the
|
|
774
832
|
* default - forgives typos and skipped characters, and while it is the
|
|
@@ -1041,6 +1099,7 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
1041
1099
|
cellSelection,
|
|
1042
1100
|
onFocusedCellChange,
|
|
1043
1101
|
filters: filterOptions,
|
|
1102
|
+
exportOptions: exportOptionsOverride,
|
|
1044
1103
|
editing,
|
|
1045
1104
|
renderDetails,
|
|
1046
1105
|
renderDetailsEstHeight = DEFAULT_DETAILS_EST_HEIGHT,
|
|
@@ -1072,6 +1131,23 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
1072
1131
|
// Resolved on the override's identity, so a module-scope dictionary costs one
|
|
1073
1132
|
// merge for the lifetime of the grid.
|
|
1074
1133
|
const labels = useMemo(() => mergeLabels(labelsOverride), [labelsOverride]);
|
|
1134
|
+
// Field by field for the same reason as `filters` below.
|
|
1135
|
+
const {
|
|
1136
|
+
format: exportFormat,
|
|
1137
|
+
fileName: exportFileName,
|
|
1138
|
+
includeHeaders: exportIncludeHeaders,
|
|
1139
|
+
columns: exportColumns,
|
|
1140
|
+
} = exportOptionsOverride ?? {};
|
|
1141
|
+
const exportOptions = useMemo(
|
|
1142
|
+
() =>
|
|
1143
|
+
resolveExportOptions({
|
|
1144
|
+
format: exportFormat,
|
|
1145
|
+
fileName: exportFileName,
|
|
1146
|
+
includeHeaders: exportIncludeHeaders,
|
|
1147
|
+
columns: exportColumns,
|
|
1148
|
+
}),
|
|
1149
|
+
[exportFormat, exportFileName, exportIncludeHeaders, exportColumns],
|
|
1150
|
+
);
|
|
1075
1151
|
// Unpacked before the memo, so the api is keyed on the five fields rather
|
|
1076
1152
|
// than on the object's identity - which is what lets `filters` be written as
|
|
1077
1153
|
// a literal, the way it reads best, without republishing every render.
|
|
@@ -1476,14 +1552,14 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
1476
1552
|
columnPinning: {
|
|
1477
1553
|
// The generated columns are structurally pinned, so they are re-applied
|
|
1478
1554
|
// on top of anything restored from storage.
|
|
1479
|
-
|
|
1555
|
+
start: [
|
|
1480
1556
|
...(rowNumbersEnabled && pinningEnabled ? [ROW_NUMBER_COLUMN_ID] : []),
|
|
1481
1557
|
...(selectColumnEnabled && pinningEnabled ? [SELECT_COLUMN_ID] : []),
|
|
1482
1558
|
...(groupColumnEnabled && pinningEnabled ? [GROUP_COLUMN_ID] : []),
|
|
1483
1559
|
...(detailsColumnEnabled && pinningEnabled ? [DETAILS_COLUMN_ID] : []),
|
|
1484
1560
|
...(
|
|
1485
|
-
persistedState.columnPinning?.
|
|
1486
|
-
options.initialState?.columnPinning?.
|
|
1561
|
+
persistedState.columnPinning?.start ??
|
|
1562
|
+
options.initialState?.columnPinning?.start ??
|
|
1487
1563
|
[]
|
|
1488
1564
|
).filter(
|
|
1489
1565
|
(id) =>
|
|
@@ -1495,10 +1571,10 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
1495
1571
|
],
|
|
1496
1572
|
// The edit lane mirrors the generated columns on the left: structurally
|
|
1497
1573
|
// pinned, outermost, re-applied over anything restored.
|
|
1498
|
-
|
|
1574
|
+
end: [
|
|
1499
1575
|
...(
|
|
1500
|
-
persistedState.columnPinning?.
|
|
1501
|
-
options.initialState?.columnPinning?.
|
|
1576
|
+
persistedState.columnPinning?.end ??
|
|
1577
|
+
options.initialState?.columnPinning?.end ??
|
|
1502
1578
|
[]
|
|
1503
1579
|
).filter((id) => id !== EDIT_COLUMN_ID),
|
|
1504
1580
|
...(editColumnEnabled && pinningEnabled ? [EDIT_COLUMN_ID] : []),
|
|
@@ -1578,42 +1654,16 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
1578
1654
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1579
1655
|
}, []);
|
|
1580
1656
|
|
|
1581
|
-
//
|
|
1582
|
-
//
|
|
1583
|
-
// One: the tree column appears with the first grouped column and goes away
|
|
1584
|
-
// with the last, so an ungrouped grid looks exactly as it did before grouping
|
|
1657
|
+
// The tree column appears with the first grouped column and goes away with
|
|
1658
|
+
// the last, so an ungrouped grid looks exactly as it did before grouping
|
|
1585
1659
|
// existed. Driven from a subscription rather than by rebuilding the column
|
|
1586
1660
|
// array, because the array is what the table is built from - deriving it from
|
|
1587
1661
|
// table state would close the loop. Visibility is the one column property
|
|
1588
1662
|
// that can be changed after the fact without touching the definitions.
|
|
1589
1663
|
//
|
|
1590
|
-
// Two, and this one is a workaround. In table-core 9.0.0-beta.21 the
|
|
1591
|
-
// per-region column APIs do not list `grouping` among their memo
|
|
1592
|
-
// dependencies, even though they all derive from `getAllLeafColumns()`, which
|
|
1593
|
-
// does:
|
|
1594
|
-
//
|
|
1595
|
-
// | API | Declares |
|
|
1596
|
-
// | --- | --- |
|
|
1597
|
-
// | `getLeft/Center/RightVisibleLeafColumns` | columns, columnPinning, columnVisibility, columnOrder |
|
|
1598
|
-
// | `getLeft/Center/RightHeaderGroups` | columnPinning, columnOrder |
|
|
1599
|
-
// | `row.getLeft/Center/RightVisibleCells` | columnPinning, columnVisibility |
|
|
1600
|
-
//
|
|
1601
|
-
// So grouping a *second* column leaves every one of them returning the
|
|
1602
|
-
// previous list: the column TanStack removed keeps its header and its grid
|
|
1603
|
-
// track, and the row cells no longer line up with them. The first grouping
|
|
1604
|
-
// appears to work only because the visibility write above happens to touch a
|
|
1605
|
-
// dependency they share.
|
|
1606
|
-
//
|
|
1607
|
-
// Re-publishing `columnVisibility` and `columnOrder` - same contents, new
|
|
1608
|
-
// identity - invalidates all three families. `columnOrder` is the only
|
|
1609
|
-
// dependency the header groups declare, and `columnVisibility` the only one
|
|
1610
|
-
// the cells do, so both are needed. Remove this once the deps are fixed
|
|
1611
|
-
// upstream; the test that fails without it groups two columns and asserts the
|
|
1612
|
-
// second one leaves the grid.
|
|
1613
|
-
//
|
|
1614
1664
|
// Writing back into the store from its own subscriber is safe: the guard is
|
|
1615
|
-
// on `grouping`'s identity, and
|
|
1616
|
-
//
|
|
1665
|
+
// on `grouping`'s identity, and the write does not touch it, so the callback
|
|
1666
|
+
// it triggers short-circuits.
|
|
1617
1667
|
useEffect(() => {
|
|
1618
1668
|
if (!groupColumnEnabled) return;
|
|
1619
1669
|
let previousGrouping = table.store.state.grouping;
|
|
@@ -1647,8 +1697,8 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
1647
1697
|
// Keeps the entry injected into a controlled `columnVisibility` (see
|
|
1648
1698
|
// requestedState) in sync with grouping.
|
|
1649
1699
|
groupingActiveRef.current = state.grouping.length > 0;
|
|
1650
|
-
// On a controlled slice the
|
|
1651
|
-
// consumer's handler; the next render must forward
|
|
1700
|
+
// On a controlled slice the write below round-trips through the
|
|
1701
|
+
// consumer's handler; the next render must forward it unstabilized.
|
|
1652
1702
|
// See republishControlledStateRef.
|
|
1653
1703
|
republishControlledStateRef.current = true;
|
|
1654
1704
|
|
|
@@ -1656,7 +1706,6 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
1656
1706
|
...old,
|
|
1657
1707
|
[GROUP_COLUMN_ID]: state.grouping.length > 0,
|
|
1658
1708
|
}));
|
|
1659
|
-
table.setColumnOrder((old) => [...old]);
|
|
1660
1709
|
});
|
|
1661
1710
|
|
|
1662
1711
|
return () => subscription.unsubscribe();
|
|
@@ -1713,6 +1762,7 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
1713
1762
|
selectionAnchorRowId: null,
|
|
1714
1763
|
focusedCell: null,
|
|
1715
1764
|
cellRange: null,
|
|
1765
|
+
exportPicker: null,
|
|
1716
1766
|
},
|
|
1717
1767
|
({ setState }) => ({
|
|
1718
1768
|
openFilterPanel: (columnId = null) =>
|
|
@@ -1727,6 +1777,10 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
1727
1777
|
filterPanelOpen: false,
|
|
1728
1778
|
filterPanelColumnId: null,
|
|
1729
1779
|
})),
|
|
1780
|
+
openExportPicker: (request) =>
|
|
1781
|
+
setState((prev) => ({ ...prev, exportPicker: request })),
|
|
1782
|
+
closeExportPicker: () =>
|
|
1783
|
+
setState((prev) => ({ ...prev, exportPicker: null })),
|
|
1730
1784
|
focusPanelFilter: (columnId) =>
|
|
1731
1785
|
setState((prev) => ({ ...prev, filterPanelColumnId: columnId })),
|
|
1732
1786
|
focusHeaderFilter: (columnId) =>
|
|
@@ -1819,12 +1873,12 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
1819
1873
|
table.setColumnSizing({ ...initial?.columnSizing });
|
|
1820
1874
|
table.setColumnOrder([...(initial?.columnOrder ?? [])]);
|
|
1821
1875
|
table.setColumnPinning({
|
|
1822
|
-
|
|
1876
|
+
start: [
|
|
1823
1877
|
...(rowNumbersEnabled && pinningEnabled ? [ROW_NUMBER_COLUMN_ID] : []),
|
|
1824
1878
|
...(selectColumnEnabled && pinningEnabled ? [SELECT_COLUMN_ID] : []),
|
|
1825
1879
|
...(groupColumnEnabled && pinningEnabled ? [GROUP_COLUMN_ID] : []),
|
|
1826
1880
|
...(detailsColumnEnabled && pinningEnabled ? [DETAILS_COLUMN_ID] : []),
|
|
1827
|
-
...(initial?.columnPinning?.
|
|
1881
|
+
...(initial?.columnPinning?.start ?? []).filter(
|
|
1828
1882
|
(id) =>
|
|
1829
1883
|
id !== ROW_NUMBER_COLUMN_ID &&
|
|
1830
1884
|
id !== SELECT_COLUMN_ID &&
|
|
@@ -1832,8 +1886,8 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
1832
1886
|
id !== GROUP_COLUMN_ID,
|
|
1833
1887
|
),
|
|
1834
1888
|
],
|
|
1835
|
-
|
|
1836
|
-
...(initial?.columnPinning?.
|
|
1889
|
+
end: [
|
|
1890
|
+
...(initial?.columnPinning?.end ?? []).filter(
|
|
1837
1891
|
(id) => id !== EDIT_COLUMN_ID,
|
|
1838
1892
|
),
|
|
1839
1893
|
...(editColumnEnabled && pinningEnabled ? [EDIT_COLUMN_ID] : []),
|
|
@@ -1857,6 +1911,7 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
1857
1911
|
edit,
|
|
1858
1912
|
features,
|
|
1859
1913
|
filters,
|
|
1914
|
+
exportOptions,
|
|
1860
1915
|
labels,
|
|
1861
1916
|
renderDetails,
|
|
1862
1917
|
renderDetailsEstHeight,
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { useSelector } from "@tanstack/react-store";
|
|
2
|
+
import { useTMDataGridContext } from "./TMDataGridContext";
|
|
3
|
+
import {
|
|
4
|
+
buildExportData,
|
|
5
|
+
countSelectedExportRows,
|
|
6
|
+
resolveExportOptions,
|
|
7
|
+
writeExportFile,
|
|
8
|
+
type TMDataGridExportOptions,
|
|
9
|
+
} from "./core/export";
|
|
10
|
+
|
|
11
|
+
/** What {@link useTMDataGridExport} returns. */
|
|
12
|
+
export type TMDataGridExportApi = {
|
|
13
|
+
/**
|
|
14
|
+
* Downloads every filtered and sorted row, all pages. `overrides` are folded
|
|
15
|
+
* over the hook's options for this one call - the column picker's chosen
|
|
16
|
+
* columns, for instance.
|
|
17
|
+
*/
|
|
18
|
+
exportAll: (overrides?: TMDataGridExportOptions) => Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Downloads the selected rows of the current view, in grid order. Resolves
|
|
21
|
+
* without a download when none is selected.
|
|
22
|
+
*/
|
|
23
|
+
exportSelected: (overrides?: TMDataGridExportOptions) => Promise<void>;
|
|
24
|
+
/** How many rows `exportSelected` would write. Subscribes to the selection. */
|
|
25
|
+
selectedCount: number;
|
|
26
|
+
/**
|
|
27
|
+
* Whether row selection is on at all - `false` under
|
|
28
|
+
* `selectionMode: "highlight"` or `enableRowSelection: false`, where a
|
|
29
|
+
* "selected rows" control has nothing to offer.
|
|
30
|
+
*/
|
|
31
|
+
canExportSelected: boolean;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The export as click handlers, for a button of your own anywhere inside the
|
|
36
|
+
* grid. The `TMDataGrid.Menu.Export*` items are this hook behind a
|
|
37
|
+
* `Menu.Item`.
|
|
38
|
+
*
|
|
39
|
+
* ```tsx
|
|
40
|
+
* function ExportButton() {
|
|
41
|
+
* const { exportAll } = useTMDataGridExport();
|
|
42
|
+
* return <Button onClick={() => void exportAll()}>Export</Button>;
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* `overrides` are folded over the grid's `exportOptions` for this caller:
|
|
47
|
+
* another format, another file name, another set of columns.
|
|
48
|
+
*/
|
|
49
|
+
export function useTMDataGridExport(
|
|
50
|
+
overrides?: TMDataGridExportOptions,
|
|
51
|
+
): TMDataGridExportApi {
|
|
52
|
+
const { table, features, exportOptions } = useTMDataGridContext();
|
|
53
|
+
const selectedCount = useSelector(table.store, () =>
|
|
54
|
+
countSelectedExportRows(table),
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const run = async (
|
|
58
|
+
rows: "all" | "selected",
|
|
59
|
+
callOverrides?: TMDataGridExportOptions,
|
|
60
|
+
) => {
|
|
61
|
+
const resolved = resolveExportOptions(
|
|
62
|
+
exportOptions,
|
|
63
|
+
overrides,
|
|
64
|
+
callOverrides,
|
|
65
|
+
);
|
|
66
|
+
const data = buildExportData({ table, rows, columns: resolved.columns });
|
|
67
|
+
if (data.columnIds.length === 0) return;
|
|
68
|
+
if (rows === "selected" && data.rows.length === 0) return;
|
|
69
|
+
await writeExportFile(data, resolved);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
exportAll: (callOverrides) => run("all", callOverrides),
|
|
74
|
+
exportSelected: (callOverrides) => run("selected", callOverrides),
|
|
75
|
+
selectedCount,
|
|
76
|
+
canExportSelected: features.rowSelection,
|
|
77
|
+
};
|
|
78
|
+
}
|