@jielga/tmdatagrid 2.0.0-beta.8 → 2.0.0
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 +1323 -796
- package/dist/index.js +4719 -3193
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/docs/adding-rows.md +132 -0
- package/docs/anatomy.md +119 -0
- package/docs/card-view.md +108 -0
- package/docs/cell-selection.md +194 -0
- package/docs/column-layout.md +182 -0
- package/docs/column-menu.md +66 -0
- package/docs/columns.md +268 -0
- package/docs/components.md +311 -0
- package/docs/draft-store.md +242 -0
- package/docs/editing.md +303 -0
- package/docs/editors.md +250 -0
- package/docs/export.md +319 -0
- package/docs/filtering.md +362 -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/migrating-to-2.md +163 -0
- package/docs/pagination.md +144 -0
- package/docs/persistence.md +114 -0
- package/docs/portfolio-rebalancer.md +94 -0
- package/docs/query-builder.md +179 -0
- package/docs/quick-search.md +84 -0
- package/docs/row-details.md +115 -0
- package/docs/row-interaction.md +149 -0
- package/docs/row-pinning.md +132 -0
- package/docs/row-selection.md +136 -0
- package/docs/row-styling.md +133 -0
- package/docs/scrolling.md +112 -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 +744 -0
- package/docs/toolbar.md +161 -0
- package/docs/use-tm-data-grid.md +361 -0
- package/package.json +22 -46
- package/skills/appearance/SKILL.md +72 -19
- package/skills/cell-selection/SKILL.md +69 -78
- package/skills/columns/SKILL.md +90 -34
- package/skills/data/SKILL.md +86 -16
- package/skills/editing/SKILL.md +83 -50
- package/skills/editing/references/common-mistakes.md +77 -69
- package/skills/editing/references/editing-api.md +31 -23
- package/skills/editing/references/editors-and-validation.md +24 -17
- package/skills/filtering/SKILL.md +148 -40
- package/skills/getting-started/SKILL.md +17 -15
- package/skills/grouping/SKILL.md +31 -16
- package/skills/options/SKILL.md +8 -8
- package/skills/rows/SKILL.md +22 -18
- package/skills/server-side/SKILL.md +170 -17
- package/skills/testing/SKILL.md +150 -32
- package/skills/testing-components/SKILL.md +230 -0
- package/skills/testing-editing/SKILL.md +240 -0
- package/src/{tmdatagrid/TMDataGridContext.ts → TMDataGridContext.ts} +7 -19
- package/src/{tmdatagrid/components → components}/TMDataGrid.module.css +7 -1
- package/src/{tmdatagrid/components → components}/TMDataGrid.tsx +38 -21
- package/src/{tmdatagrid/components → components}/TMDataGridCellEditor.tsx +73 -7
- package/src/{tmdatagrid/components → components}/TMDataGridColumnsPanel.module.css +5 -1
- package/src/{tmdatagrid/components → components}/TMDataGridColumnsPanel.tsx +47 -55
- package/src/{tmdatagrid/components → components}/TMDataGridDetailsColumn.tsx +9 -55
- package/src/{tmdatagrid/components → components}/TMDataGridDraftActions.tsx +41 -24
- package/src/{tmdatagrid/components → components}/TMDataGridEditColumn.tsx +23 -63
- package/src/components/TMDataGridEntryRows.tsx +354 -0
- package/src/components/TMDataGridExportPicker.module.css +77 -0
- package/src/components/TMDataGridExportPicker.tsx +234 -0
- package/src/components/TMDataGridFilterPanel.module.css +54 -0
- package/src/components/TMDataGridFilterPanel.tsx +348 -0
- package/src/{tmdatagrid/components → components}/TMDataGridFilterPills.tsx +15 -8
- package/src/components/TMDataGridFilterSurface.module.css +54 -0
- package/src/components/TMDataGridFilterSurface.tsx +167 -0
- package/src/{tmdatagrid/components → components}/TMDataGridFooter.tsx +53 -90
- package/src/{tmdatagrid/components → components}/TMDataGridGroupColumn.tsx +9 -72
- package/src/{tmdatagrid/components → components}/TMDataGridHeaderCell.module.css +12 -2
- package/src/{tmdatagrid/components → components}/TMDataGridHeaderCell.tsx +58 -21
- package/src/components/TMDataGridHeaderFilterRow.module.css +51 -0
- package/src/components/TMDataGridHeaderFilterRow.tsx +301 -0
- package/src/components/TMDataGridMenu.tsx +357 -0
- package/src/{tmdatagrid/components → components}/TMDataGridSelectColumn.tsx +15 -53
- package/src/{tmdatagrid/components → components}/TMDataGridTable.module.css +88 -65
- package/src/{tmdatagrid/components → components}/TMDataGridTable.tsx +579 -165
- package/src/{tmdatagrid/components → components}/TMDataGridToolbar.module.css +5 -0
- package/src/components/TMDataGridToolbar.tsx +181 -0
- package/src/{tmdatagrid/components → components}/editors/TMDataGridBooleanEditor.tsx +3 -3
- package/src/{tmdatagrid/components → components}/editors/TMDataGridDateEditor.tsx +3 -3
- package/src/{tmdatagrid/components → components}/editors/TMDataGridMultiSelectEditor.tsx +3 -3
- package/src/{tmdatagrid/components → components}/editors/TMDataGridNumberEditor.tsx +3 -3
- package/src/{tmdatagrid/components → components}/editors/TMDataGridSelectEditor.tsx +3 -3
- package/src/{tmdatagrid/components → components}/editors/TMDataGridStringEditor.tsx +3 -3
- package/src/{tmdatagrid/components → components}/editors/editorShared.ts +16 -2
- package/src/{tmdatagrid/components → components}/filters/DgAutocompleteFilter.tsx +5 -4
- package/src/{tmdatagrid/components → components}/filters/DgDateRangeFilter.tsx +22 -5
- package/src/{tmdatagrid/components → components}/filters/DgRangeSliderFilter.tsx +5 -1
- package/src/{tmdatagrid/components → components}/filters/DgTriStateFilter.tsx +5 -1
- package/src/{tmdatagrid/components → components}/filters/TMDataGridFilterValueInput.tsx +44 -28
- package/src/components/filters/controlLayout.ts +32 -0
- package/src/components/filters/filterControlFor.ts +65 -0
- package/src/components/generatedColumns.tsx +187 -0
- package/src/{tmdatagrid/components → components}/icons.ts +1 -0
- package/src/{tmdatagrid/components → components}/sticky.module.css +44 -0
- package/src/components/useHideableColumns.ts +52 -0
- package/src/{tmdatagrid/core → core}/autosize.ts +5 -2
- package/src/{tmdatagrid/core → core}/capabilities.ts +5 -5
- package/src/{tmdatagrid/core → core}/columnOptions.ts +60 -8
- package/src/{tmdatagrid/core → core}/columnOrdering.ts +33 -14
- package/src/{tmdatagrid/core → core}/columnUtils.ts +44 -5
- package/src/core/controlledStateSync.ts +108 -0
- package/src/core/deletedRows.ts +34 -0
- package/src/core/dom.ts +74 -0
- package/src/{tmdatagrid/core → core}/editEngine.ts +1172 -388
- package/src/{tmdatagrid/core → core}/editorFocus.ts +8 -4
- package/src/core/export.ts +704 -0
- package/src/{tmdatagrid/core → core}/filterControls.ts +38 -1
- package/src/{tmdatagrid/core → core}/filterOperators.ts +64 -1
- package/src/core/filterSurface.ts +99 -0
- package/src/{tmdatagrid/core → core}/grouping.ts +21 -0
- package/src/{tmdatagrid/core → core}/labels.ts +51 -6
- package/src/{tmdatagrid/core → core}/labelsSv.ts +27 -6
- package/src/core/pageReset.ts +120 -0
- package/src/core/pagination.ts +81 -0
- 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} +70 -36
- package/src/{tmdatagrid/useTMDataGrid.tsx → useTMDataGrid.tsx} +534 -123
- package/src/useTMDataGridExport.ts +78 -0
- package/src/tmdatagrid/components/TMDataGridEntryRows.tsx +0 -298
- package/src/tmdatagrid/components/TMDataGridFilterPanel.module.css +0 -35
- package/src/tmdatagrid/components/TMDataGridFilterPanel.tsx +0 -354
- package/src/tmdatagrid/components/TMDataGridToolbar.tsx +0 -161
- package/src/tmdatagrid/core/cellExport.ts +0 -320
- /package/src/{tmdatagrid/components → components}/TMDataGridDetailsColumn.module.css +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridFilterPills.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}/TMDataGridRowNumberColumn.tsx +0 -0
- /package/src/{tmdatagrid/components → components}/TMDataGridSearch.tsx +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}/controlledState.ts +0 -0
- /package/src/{tmdatagrid/core → core}/draftCellContext.ts +0 -0
- /package/src/{tmdatagrid/core → core}/expanding.ts +0 -0
- /package/src/{tmdatagrid/core → core}/matchHighlight.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
|
@@ -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
|
+
}
|
|
@@ -1,298 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
flexRender,
|
|
3
|
-
useTable,
|
|
4
|
-
type Column,
|
|
5
|
-
type Row,
|
|
6
|
-
} from "@tanstack/react-table";
|
|
7
|
-
import { useSelector } from "@tanstack/react-store";
|
|
8
|
-
import { useLayoutEffect, useMemo, useRef } from "react";
|
|
9
|
-
import classes from "./TMDataGridTable.module.css";
|
|
10
|
-
import sticky from "./sticky.module.css";
|
|
11
|
-
import { type TMDataGridRowData, useTMDataGridContext } from "../TMDataGridContext";
|
|
12
|
-
import {
|
|
13
|
-
getColumnAlign,
|
|
14
|
-
isColumnEditableForRow,
|
|
15
|
-
isControlColumn,
|
|
16
|
-
} from "../core/columnUtils";
|
|
17
|
-
import type { TMDataGridEditApi } from "../core/editEngine";
|
|
18
|
-
import { focusEditorContent } from "../core/editorFocus";
|
|
19
|
-
import {
|
|
20
|
-
tmDataGridFeatures,
|
|
21
|
-
type TMDataGridFeatures,
|
|
22
|
-
} from "../useTMDataGrid";
|
|
23
|
-
import { TMDataGridCellEditor } from "./TMDataGridCellEditor";
|
|
24
|
-
import { EDIT_COLUMN_ID } from "./TMDataGridEditColumn";
|
|
25
|
-
import type { TMDataGridColumnLayout } from "./TMDataGridTable";
|
|
26
|
-
|
|
27
|
-
type ErasedColumn = Column<TMDataGridFeatures, TMDataGridRowData, unknown>;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Whether an entry cell edits. `edit.canEditCell` asks the main table for
|
|
31
|
-
* the row, and an entry row is precisely not there yet - so the structural
|
|
32
|
-
* half of the same rule is applied to the entry table's own row.
|
|
33
|
-
*/
|
|
34
|
-
function isEntryCellEditable(
|
|
35
|
-
row: Row<TMDataGridFeatures, TMDataGridRowData>,
|
|
36
|
-
column: ErasedColumn,
|
|
37
|
-
edit: TMDataGridEditApi,
|
|
38
|
-
): boolean {
|
|
39
|
-
if (!edit.isColumnEditable(column)) return false;
|
|
40
|
-
return isColumnEditableForRow(column, row);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* The sticky entry block - one row of open editors per `edit.addRow()`,
|
|
45
|
-
* pinned under the header. The one place stickiness is genuinely required:
|
|
46
|
-
* an existing row that scrolls away has a place to scroll back to, a row
|
|
47
|
-
* being typed into does not exist anywhere else.
|
|
48
|
-
*
|
|
49
|
-
* A second, tiny table instance over the new rows' seed values - same
|
|
50
|
-
* columns, its own `useTable`, no sorting or filtering ever exercised - so
|
|
51
|
-
* these are real `Cell`s and the editor host, the typed editors and the
|
|
52
|
-
* validators all apply unchanged. The forms live in the same engine map as
|
|
53
|
-
* every other draft, keyed by their temporary ids.
|
|
54
|
-
*
|
|
55
|
-
* Enter commits the entry - `onRowAdd`, or a park under `editing.draft`,
|
|
56
|
-
* where `saveDrafts` reports it in `created`; Escape discards it. The edit
|
|
57
|
-
* lane, when present, offers the same pair as buttons.
|
|
58
|
-
*/
|
|
59
|
-
export function TMDataGridEntryRows({
|
|
60
|
-
orderedColumns,
|
|
61
|
-
layoutFor,
|
|
62
|
-
rowHeight,
|
|
63
|
-
}: {
|
|
64
|
-
orderedColumns: ReadonlyArray<ErasedColumn>;
|
|
65
|
-
layoutFor: (columnId: string) => TMDataGridColumnLayout;
|
|
66
|
-
rowHeight: number;
|
|
67
|
-
}) {
|
|
68
|
-
const { table, edit, features } = useTMDataGridContext();
|
|
69
|
-
const newRows = useSelector(edit.store, (state) => state.newRows);
|
|
70
|
-
// The reopen gesture: `begin` on a committed entry row flips it back to
|
|
71
|
-
// editors and names the cell double-clicked - where the caret goes.
|
|
72
|
-
const activeEntry = useSelector(edit.store, (state) =>
|
|
73
|
-
state.active !== null &&
|
|
74
|
-
state.newRows.some(
|
|
75
|
-
(newRow) => newRow.tempId === state.active?.rowId && !newRow.committed,
|
|
76
|
-
)
|
|
77
|
-
? state.active
|
|
78
|
-
: null,
|
|
79
|
-
);
|
|
80
|
-
const blockRef = useRef<HTMLDivElement>(null);
|
|
81
|
-
/** The entry row the caret has already been placed in. */
|
|
82
|
-
const focusedTempIdRef = useRef<string | null>(null);
|
|
83
|
-
/** The reopen target (`rowId:columnId`) the caret has already landed in. */
|
|
84
|
-
const focusedActiveRef = useRef<string | null>(null);
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* The caret goes into a row the moment `edit.addRow()` opens it, landing in
|
|
88
|
-
* its first editable cell - the same placement the main table makes for a
|
|
89
|
-
* row opened by a gesture, and made here for the same reason: an editor is
|
|
90
|
-
* free not to focus itself, and then a new row appeared with the caret
|
|
91
|
-
* still outside it.
|
|
92
|
-
*/
|
|
93
|
-
useLayoutEffect(() => {
|
|
94
|
-
const newest = newRows.at(-1)?.tempId;
|
|
95
|
-
if (newest === undefined) {
|
|
96
|
-
focusedTempIdRef.current = null;
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
if (focusedTempIdRef.current === newest) return;
|
|
100
|
-
const block = blockRef.current;
|
|
101
|
-
if (block === null) return;
|
|
102
|
-
const editor = block.querySelector<HTMLElement>(
|
|
103
|
-
`[data-dg-part="editor"][data-row-id="${CSS.escape(newest)}"]`,
|
|
104
|
-
);
|
|
105
|
-
// Not mounted yet; the next render tries again, as the table's does.
|
|
106
|
-
if (editor === null) return;
|
|
107
|
-
focusedTempIdRef.current = newest;
|
|
108
|
-
focusEditorContent(editor);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* The caret for a reopen: `begin` on a committed row re-arms its editors
|
|
113
|
-
* and the double-clicked cell's editor should hold the caret, not the
|
|
114
|
-
* row's first. Keyed separately from the add effect above - the row was
|
|
115
|
-
* already focused once when it was added.
|
|
116
|
-
*/
|
|
117
|
-
useLayoutEffect(() => {
|
|
118
|
-
if (activeEntry === null) {
|
|
119
|
-
focusedActiveRef.current = null;
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
const key = `${activeEntry.rowId}:${activeEntry.columnId ?? ""}`;
|
|
123
|
-
if (focusedActiveRef.current === key) return;
|
|
124
|
-
const block = blockRef.current;
|
|
125
|
-
if (block === null) return;
|
|
126
|
-
const editor = block.querySelector<HTMLElement>(
|
|
127
|
-
activeEntry.columnId !== null
|
|
128
|
-
? `[data-dg-part="editor"][data-row-id="${CSS.escape(activeEntry.rowId)}"][data-column-id="${CSS.escape(activeEntry.columnId)}"]`
|
|
129
|
-
: `[data-dg-part="editor"][data-row-id="${CSS.escape(activeEntry.rowId)}"]`,
|
|
130
|
-
);
|
|
131
|
-
// Not mounted yet; the next render tries again, as the add effect does.
|
|
132
|
-
if (editor === null) return;
|
|
133
|
-
focusedActiveRef.current = key;
|
|
134
|
-
focusEditorContent(editor);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
// Open (uncommitted) rows keep the seed values frozen at addRow - the live values
|
|
138
|
-
// belong to the forms, which the editors read directly, and this table only
|
|
139
|
-
// provides row and cell identity. A committed row's cells render values, so
|
|
140
|
-
// there the draft itself is the row; the memo recomputes on every
|
|
141
|
-
// commit/reopen because either flips `newRows`' identity.
|
|
142
|
-
const data = useMemo(
|
|
143
|
-
() =>
|
|
144
|
-
newRows.map(
|
|
145
|
-
({ tempId, committed }) =>
|
|
146
|
-
((committed
|
|
147
|
-
? edit.getForm(tempId)?.state.values
|
|
148
|
-
: edit.getForm(tempId)?.options.defaultValues) ??
|
|
149
|
-
{}) as TMDataGridRowData,
|
|
150
|
-
),
|
|
151
|
-
[newRows, edit],
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
const entryTable = useTable({
|
|
155
|
-
features: tmDataGridFeatures,
|
|
156
|
-
columns: table.options.columns,
|
|
157
|
-
data,
|
|
158
|
-
getRowId: (_row, index) => newRows[index]?.tempId ?? String(index),
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
if (newRows.length === 0) return null;
|
|
162
|
-
|
|
163
|
-
const entryRows = entryTable.getCoreRowModel().rows;
|
|
164
|
-
const committedById = new Map(
|
|
165
|
-
newRows.map((newRow) => [newRow.tempId, newRow.committed]),
|
|
166
|
-
);
|
|
167
|
-
// A row being *typed* into is always sticky - it exists nowhere else to
|
|
168
|
-
// scroll back to. A committed row joins the scrolling flow unless
|
|
169
|
-
// `newRowsSticky` keeps it pinned, so entering many rows cannot fill the
|
|
170
|
-
// viewport with sticky chrome.
|
|
171
|
-
const stickyRows = entryRows.filter(
|
|
172
|
-
(entryRow) =>
|
|
173
|
-
features.editNewRowsSticky || committedById.get(entryRow.id) !== true,
|
|
174
|
-
);
|
|
175
|
-
const flowRows = features.editNewRowsSticky
|
|
176
|
-
? []
|
|
177
|
-
: entryRows.filter((entryRow) => committedById.get(entryRow.id) === true);
|
|
178
|
-
|
|
179
|
-
const renderEntryRow = (
|
|
180
|
-
entryRow: (typeof entryRows)[number],
|
|
181
|
-
pinnedZ: string,
|
|
182
|
-
) => {
|
|
183
|
-
const cellsById = new Map(
|
|
184
|
-
entryRow.getAllCells().map((cell) => [cell.column.id, cell]),
|
|
185
|
-
);
|
|
186
|
-
const committed = committedById.get(entryRow.id) === true;
|
|
187
|
-
return (
|
|
188
|
-
<div
|
|
189
|
-
key={entryRow.id}
|
|
190
|
-
role="row"
|
|
191
|
-
data-dg-part="entry-row"
|
|
192
|
-
data-row-id={entryRow.id}
|
|
193
|
-
data-new
|
|
194
|
-
data-committed={committed}
|
|
195
|
-
// The same marker body rows carry once committed, so one selector
|
|
196
|
-
// reaches everything parked in the draft store.
|
|
197
|
-
data-draft={committed}
|
|
198
|
-
className={classes.entryRow}
|
|
199
|
-
>
|
|
200
|
-
{orderedColumns.map((column) => {
|
|
201
|
-
const cell = cellsById.get(column.id);
|
|
202
|
-
const layout = layoutFor(column.id);
|
|
203
|
-
const editable =
|
|
204
|
-
cell !== undefined && isEntryCellEditable(entryRow, column, edit);
|
|
205
|
-
return (
|
|
206
|
-
<div
|
|
207
|
-
key={column.id}
|
|
208
|
-
role="cell"
|
|
209
|
-
data-column-id={column.id}
|
|
210
|
-
data-align={getColumnAlign(column)}
|
|
211
|
-
data-control-column={isControlColumn(column.id)}
|
|
212
|
-
// A committed row re-opens where it is double-clicked, the
|
|
213
|
-
// same gesture a body cell answers - and, like a body cell, a
|
|
214
|
-
// cell that takes no edit answers nothing.
|
|
215
|
-
onDoubleClick={
|
|
216
|
-
committed && editable
|
|
217
|
-
? () =>
|
|
218
|
-
edit.begin({
|
|
219
|
-
rowId: entryRow.id,
|
|
220
|
-
columnId: column.id,
|
|
221
|
-
})
|
|
222
|
-
: undefined
|
|
223
|
-
}
|
|
224
|
-
className={[
|
|
225
|
-
classes.entryCell,
|
|
226
|
-
layout.isBoundary && layout.pinnedAt === "left"
|
|
227
|
-
? sticky.stickyLeft
|
|
228
|
-
: "",
|
|
229
|
-
layout.isBoundary && layout.pinnedAt === "right"
|
|
230
|
-
? sticky.stickyRight
|
|
231
|
-
: "",
|
|
232
|
-
]
|
|
233
|
-
.filter(Boolean)
|
|
234
|
-
.join(" ")}
|
|
235
|
-
style={{
|
|
236
|
-
minHeight: rowHeight,
|
|
237
|
-
left: layout.pinnedAt === "left" ? layout.offset : undefined,
|
|
238
|
-
right: layout.pinnedAt === "right" ? layout.offset : undefined,
|
|
239
|
-
position: layout.pinnedAt ? "sticky" : undefined,
|
|
240
|
-
zIndex: layout.pinnedAt ? pinnedZ : undefined,
|
|
241
|
-
}}
|
|
242
|
-
>
|
|
243
|
-
{cell !== undefined && column.id === EDIT_COLUMN_ID ? (
|
|
244
|
-
// The lane's cell - the entry row's controls.
|
|
245
|
-
flexRender(cell.column.columnDef.cell, cell.getContext())
|
|
246
|
-
) : committed && cell !== undefined ? (
|
|
247
|
-
// Entered, awaiting Save all: a value row through the
|
|
248
|
-
// columns' own renderers, over the draft the memo above
|
|
249
|
-
// fed this table.
|
|
250
|
-
<span className={classes.cellContent}>
|
|
251
|
-
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
252
|
-
</span>
|
|
253
|
-
) : editable && cell !== undefined ? (
|
|
254
|
-
<TMDataGridCellEditor
|
|
255
|
-
cell={cell}
|
|
256
|
-
row={entryRow}
|
|
257
|
-
takeSeedText={() => undefined}
|
|
258
|
-
onClose={() => {}}
|
|
259
|
-
inEntryBlock
|
|
260
|
-
/>
|
|
261
|
-
) : null}
|
|
262
|
-
</div>
|
|
263
|
-
);
|
|
264
|
-
})}
|
|
265
|
-
</div>
|
|
266
|
-
);
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
return (
|
|
270
|
-
<>
|
|
271
|
-
{stickyRows.length > 0 && (
|
|
272
|
-
<div
|
|
273
|
-
ref={blockRef}
|
|
274
|
-
role="rowgroup"
|
|
275
|
-
data-dg-entry-block
|
|
276
|
-
className={classes.entryBlock}
|
|
277
|
-
>
|
|
278
|
-
{stickyRows.map((entryRow) =>
|
|
279
|
-
renderEntryRow(entryRow, "var(--dg-z-pinned-row-pinned-cell, 5)"),
|
|
280
|
-
)}
|
|
281
|
-
</div>
|
|
282
|
-
)}
|
|
283
|
-
{flowRows.length > 0 && (
|
|
284
|
-
<div
|
|
285
|
-
role="rowgroup"
|
|
286
|
-
data-dg-entry-flow-block
|
|
287
|
-
className={classes.entryFlowBlock}
|
|
288
|
-
>
|
|
289
|
-
{/* In flow, so a pinned cell stacks like a body row's, under the
|
|
290
|
-
sticky blocks it scrolls past. */}
|
|
291
|
-
{flowRows.map((entryRow) =>
|
|
292
|
-
renderEntryRow(entryRow, "var(--dg-z-pinned-cell, 2)"),
|
|
293
|
-
)}
|
|
294
|
-
</div>
|
|
295
|
-
)}
|
|
296
|
-
</>
|
|
297
|
-
);
|
|
298
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/* Floats over the first body rows, anchored to `.tableWrapper`. Sits just
|
|
2
|
-
below the header row, so its offset follows the size scale rather than a
|
|
3
|
-
fixed pixel count. */
|
|
4
|
-
.filterPanel {
|
|
5
|
-
position: absolute;
|
|
6
|
-
top: calc(var(--dg-header-height) + 2px);
|
|
7
|
-
left: var(--mantine-spacing-md);
|
|
8
|
-
z-index: 5;
|
|
9
|
-
padding: var(--mantine-spacing-sm);
|
|
10
|
-
border-radius: var(--mantine-radius-md);
|
|
11
|
-
border: 1px solid var(--mantine-color-default-border);
|
|
12
|
-
background-color: var(--mantine-color-body);
|
|
13
|
-
box-shadow: var(--mantine-shadow-md);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.filterRow {
|
|
17
|
-
display: flex;
|
|
18
|
-
align-items: flex-end;
|
|
19
|
-
gap: var(--mantine-spacing-xs);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.filterPanelHeader {
|
|
23
|
-
display: flex;
|
|
24
|
-
align-items: center;
|
|
25
|
-
justify-content: space-between;
|
|
26
|
-
gap: var(--mantine-spacing-md);
|
|
27
|
-
padding-bottom: var(--mantine-spacing-xs);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.filterPanelFooter {
|
|
31
|
-
display: flex;
|
|
32
|
-
align-items: center;
|
|
33
|
-
justify-content: space-between;
|
|
34
|
-
gap: var(--mantine-spacing-md);
|
|
35
|
-
}
|