@jielga/tmdatagrid 2.0.0-beta.0 → 2.0.0-beta.2
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 +32 -34
- package/dist/index.d.ts +164 -102
- package/dist/index.js +2060 -1705
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/skills/appearance/SKILL.md +37 -34
- package/skills/cell-selection/SKILL.md +19 -19
- package/skills/columns/SKILL.md +9 -9
- package/skills/data/SKILL.md +53 -53
- package/skills/editing/SKILL.md +152 -311
- package/skills/editing/references/common-mistakes.md +177 -0
- package/skills/editing/references/editing-api.md +56 -28
- package/skills/editing/references/editors-and-validation.md +26 -19
- package/skills/filtering/SKILL.md +51 -50
- package/skills/getting-started/SKILL.md +10 -10
- package/skills/grouping/SKILL.md +41 -43
- package/skills/options/SKILL.md +4 -4
- package/skills/rows/SKILL.md +59 -59
- package/skills/rows/references/rows-api.md +7 -7
- package/skills/server-side/SKILL.md +1 -1
- package/skills/testing/SKILL.md +11 -10
- package/src/tmdatagrid/components/TMDataGrid.module.css +13 -1
- package/src/tmdatagrid/components/TMDataGridCellEditor.tsx +20 -8
- package/src/tmdatagrid/components/TMDataGridColumnsPanel.tsx +29 -18
- package/src/tmdatagrid/components/TMDataGridDetailsColumn.tsx +5 -8
- package/src/tmdatagrid/components/TMDataGridEditActions.tsx +2 -2
- package/src/tmdatagrid/components/TMDataGridEditColumn.tsx +246 -86
- package/src/tmdatagrid/components/TMDataGridEntryRows.tsx +176 -77
- package/src/tmdatagrid/components/TMDataGridHeaderCell.tsx +11 -6
- package/src/tmdatagrid/components/TMDataGridSelectColumn.tsx +9 -5
- package/src/tmdatagrid/components/TMDataGridTable.module.css +47 -3
- package/src/tmdatagrid/components/TMDataGridTable.tsx +101 -40
- package/src/tmdatagrid/components/editors/TMDataGridNumberEditor.tsx +1 -1
- package/src/tmdatagrid/components/icons.ts +1 -0
- package/src/tmdatagrid/core/autosize.ts +30 -6
- package/src/tmdatagrid/core/capabilities.ts +15 -5
- package/src/tmdatagrid/core/cellExport.ts +6 -7
- package/src/tmdatagrid/core/cellNavigation.ts +2 -2
- package/src/tmdatagrid/core/cellRange.ts +6 -6
- package/src/tmdatagrid/core/columnOrdering.ts +30 -1
- package/src/tmdatagrid/core/columnUtils.ts +14 -0
- package/src/tmdatagrid/core/draftCellContext.ts +68 -0
- package/src/tmdatagrid/core/editEngine.ts +111 -37
- package/src/tmdatagrid/core/filterOperators.ts +6 -6
- package/src/tmdatagrid/core/labels.ts +13 -1
- package/src/tmdatagrid/core/labelsSv.ts +4 -0
- package/src/tmdatagrid/core/matchHighlight.ts +3 -3
- package/src/tmdatagrid/core/persistence.ts +3 -3
- package/src/tmdatagrid/core/rowSelection.ts +3 -3
- package/src/tmdatagrid/index.ts +3 -1
- package/src/tmdatagrid/useTMDataGrid.tsx +141 -99
|
@@ -51,7 +51,7 @@ import {
|
|
|
51
51
|
createEditEngine,
|
|
52
52
|
type TMDataGridEditApi,
|
|
53
53
|
type TMDataGridEditCommitArgs,
|
|
54
|
-
type
|
|
54
|
+
type TMDataGridEditCommitDraftsArgs,
|
|
55
55
|
type TMDataGridEditEngineContext,
|
|
56
56
|
type TMDataGridColumnEditOptions,
|
|
57
57
|
type TMDataGridEditMode,
|
|
@@ -64,7 +64,7 @@ import {
|
|
|
64
64
|
type TMDataGridColumnType,
|
|
65
65
|
tmDataGridFilterFn,
|
|
66
66
|
} from "./core/filterOperators";
|
|
67
|
-
import { getColumnDefaultOperator } from "./core/columnUtils";
|
|
67
|
+
import { getColumnDefaultOperator, isControlColumn } from "./core/columnUtils";
|
|
68
68
|
import type { TMDataGridColumnFilterOptions } from "./core/filterControls";
|
|
69
69
|
import {
|
|
70
70
|
createFuzzyRankedSortedRowModel,
|
|
@@ -123,14 +123,14 @@ import {
|
|
|
123
123
|
const PERSIST_DEBOUNCE_MS = 200;
|
|
124
124
|
|
|
125
125
|
/**
|
|
126
|
-
* Per-column configuration the
|
|
126
|
+
* Per-column configuration the grid's own components read.
|
|
127
127
|
*
|
|
128
|
-
*
|
|
128
|
+
* The filter and edit stages each get a namespace, `filter` and `edit`,
|
|
129
129
|
* mirroring the feature's runtime API. What the column *is* stays flat:
|
|
130
130
|
* `label`, `type`, `options`, `align`, `flex`, `autoSize`, `enableOrdering`.
|
|
131
|
-
* `type` and `options`
|
|
132
|
-
*
|
|
133
|
-
*
|
|
131
|
+
* `type` and `options` are read by both stages, so one declaration of each
|
|
132
|
+
* feeds the filter panel and the cell editor, which is why they sit outside
|
|
133
|
+
* both namespaces.
|
|
134
134
|
*/
|
|
135
135
|
export type TMDataGridColumnMeta = {
|
|
136
136
|
/** Name shown in menus and the column manager. Falls back to a string header. */
|
|
@@ -388,7 +388,7 @@ export type TMDataGridApi<TData extends RowData> = {
|
|
|
388
388
|
* The edit engine - open forms, dirty/error projections, and the verbs
|
|
389
389
|
* (`begin`, `commit`, `cancel`, `submitAll`). `edit.getForm(rowId)` hands
|
|
390
390
|
* out the same TanStack Form the inline editors write through, so a drawer
|
|
391
|
-
* or detail panel can share a row's draft. Inert until `
|
|
391
|
+
* or detail panel can share a row's draft. Inert until `editing` is set.
|
|
392
392
|
*/
|
|
393
393
|
edit: TMDataGridEditApi;
|
|
394
394
|
/** Table-level feature switches, re-read from options on every render. */
|
|
@@ -431,20 +431,14 @@ export type TMDataGridApi<TData extends RowData> = {
|
|
|
431
431
|
*/
|
|
432
432
|
scrollToRow: (args: TMDataGridScrollToRowArgs) => boolean;
|
|
433
433
|
/**
|
|
434
|
-
* @internal Wiring for `TMDataGrid.Table`, which
|
|
435
|
-
* fills this in. Not part of the
|
|
434
|
+
* @internal Wiring for `TMDataGrid.Table`, which holds the virtualizer and
|
|
435
|
+
* fills this in. Not part of the public API.
|
|
436
436
|
*/
|
|
437
437
|
scrollerRef: MutableRefObject<TMDataGridScroller>;
|
|
438
438
|
};
|
|
439
439
|
|
|
440
|
-
/** The editing
|
|
440
|
+
/** The editing members every mode shares. See {@link TMDataGridEditingOptions}. */
|
|
441
441
|
type TMDataGridEditingCallbacks<TData extends RowData> = {
|
|
442
|
-
/**
|
|
443
|
-
* `getRowId` stops being optional once editing is on: the forms are keyed
|
|
444
|
-
* by row id and live outside the DOM, and the index fallback points at a
|
|
445
|
-
* different record after any sort.
|
|
446
|
-
*/
|
|
447
|
-
getRowId: NonNullable<TableOptions<TMDataGridFeatures, TData>["getRowId"]>;
|
|
448
442
|
/**
|
|
449
443
|
* Form-level validators for the whole editing row - where cross-field
|
|
450
444
|
* rules live. TanStack Form's own vocabulary, Standard Schema included:
|
|
@@ -470,12 +464,10 @@ type TMDataGridEditingCallbacks<TData extends RowData> = {
|
|
|
470
464
|
* draft visible with a busy marker - and a rejection keeps the form open
|
|
471
465
|
* with the error on the row.
|
|
472
466
|
*
|
|
473
|
-
* `changes` is the per-field diff (one entry in cell mode) for
|
|
474
|
-
*
|
|
467
|
+
* `changes` is the per-field diff (one entry in cell mode), for a PATCH.
|
|
468
|
+
* `value` is the entire edited row, for saving a record.
|
|
475
469
|
*/
|
|
476
|
-
|
|
477
|
-
args: TMDataGridEditCommitArgs<TData>,
|
|
478
|
-
) => void | Promise<void>;
|
|
470
|
+
onCommit?: (args: TMDataGridEditCommitArgs<TData>) => void | Promise<void>;
|
|
479
471
|
/**
|
|
480
472
|
* Seed values for `edit.addRow()` - the entry row's starting point. A
|
|
481
473
|
* function is called per added row (fresh timestamps, empty arrays).
|
|
@@ -483,13 +475,13 @@ type TMDataGridEditingCallbacks<TData extends RowData> = {
|
|
|
483
475
|
newRowDefaults?: TData | (() => TData);
|
|
484
476
|
/**
|
|
485
477
|
* Called when an entry row commits: `Enter` or the lane's ✓ under the
|
|
486
|
-
* immediate modes, `submitAll` under
|
|
478
|
+
* immediate modes, `submitAll` under draft. Create the record and let it
|
|
487
479
|
* arrive back through `data`; the engine's `tempId` never leaves the grid.
|
|
488
480
|
*/
|
|
489
481
|
onRowAdd?: (args: TMDataGridRowAddArgs<TData>) => void | Promise<void>;
|
|
490
482
|
/**
|
|
491
483
|
* Called by `edit.deleteRow` under the immediate modes - confirmation, if
|
|
492
|
-
* any, belongs in here. Under
|
|
484
|
+
* any, belongs in here. Under draft, deletions accumulate in
|
|
493
485
|
* `edit.state.deletedRowIds` instead and are reported by `submitAll`.
|
|
494
486
|
* Setting this also puts the trash can in the edit lane.
|
|
495
487
|
*/
|
|
@@ -497,21 +489,24 @@ type TMDataGridEditingCallbacks<TData extends RowData> = {
|
|
|
497
489
|
};
|
|
498
490
|
|
|
499
491
|
/**
|
|
500
|
-
* The editing
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
* required; and `onEditCommitBatch` exists only under `"batch"` - the one
|
|
504
|
-
* mode whose `submitAll` calls it.
|
|
505
|
-
*
|
|
506
|
-
* `editMode` itself turns cell editing on and picks how commits happen. Off
|
|
507
|
-
* by default.
|
|
492
|
+
* The `editing` option: one object that turns editing on and holds
|
|
493
|
+
* everything about it. `mode` picks what counts as a commit and which
|
|
494
|
+
* controls trigger it; the other members act within that mode.
|
|
508
495
|
*
|
|
509
496
|
* | Mode | Commit | Cancel |
|
|
510
497
|
* | ---- | ------ | ------ |
|
|
511
498
|
* | `"cell"` | Enter, Tab, blur - Sheets | Escape |
|
|
512
499
|
* | `"cellConfirm"` | ✓ or Enter only; blur keeps the draft | ✕ or Escape |
|
|
513
500
|
* | `"row"` | Save in the edit lane, or Ctrl+Enter | Cancel, or Escape |
|
|
514
|
-
* | `"
|
|
501
|
+
* | `"draft"` | `edit.submitAll()` | `edit.cancelAll()` |
|
|
502
|
+
*
|
|
503
|
+
* Setting `editing` makes `getRowId` required - drafts are keyed by row id,
|
|
504
|
+
* and the index fallback would name a different record after any sort - and
|
|
505
|
+
* `onCommitDrafts` exists only under `mode: "draft"`, the one mode whose
|
|
506
|
+
* `submitAll` calls it.
|
|
507
|
+
*
|
|
508
|
+
* The object may be written inline: the callbacks are read through a ref
|
|
509
|
+
* every render, so its identity does not matter.
|
|
515
510
|
*
|
|
516
511
|
* One TanStack Form per editing row; drafts survive scrolling because the
|
|
517
512
|
* forms live outside the DOM, keyed by row id. Which columns edit, and with
|
|
@@ -520,39 +515,56 @@ type TMDataGridEditingCallbacks<TData extends RowData> = {
|
|
|
520
515
|
* override the rest.
|
|
521
516
|
*/
|
|
522
517
|
export type TMDataGridEditingOptions<TData extends RowData> =
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
518
|
+
TMDataGridEditingCallbacks<TData> &
|
|
519
|
+
(
|
|
520
|
+
| {
|
|
521
|
+
mode: "draft";
|
|
522
|
+
/**
|
|
523
|
+
* Draft mode's save, called once by `edit.submitAll()` with every
|
|
524
|
+
* valid dirty row. Without it, `submitAll` falls back to the per-row
|
|
525
|
+
* {@link TMDataGridEditingCallbacks.onCommit} loop. Rows failing
|
|
526
|
+
* validation stay open either way; a rejection keeps every draft.
|
|
527
|
+
*/
|
|
528
|
+
onCommitDrafts?: (
|
|
529
|
+
args: TMDataGridEditCommitDraftsArgs<TData>,
|
|
530
|
+
) => void | Promise<void>;
|
|
531
|
+
/**
|
|
532
|
+
* Keep confirmed entry rows pinned in the sticky entry block until
|
|
533
|
+
* Save all. Off by default: a confirmed row joins the scrolling
|
|
534
|
+
* flow above the body rows instead - the block a row is *typed*
|
|
535
|
+
* into is always sticky, but entered rows scroll, so entering many
|
|
536
|
+
* cannot fill the viewport with sticky chrome.
|
|
537
|
+
*/
|
|
538
|
+
newRowsSticky?: boolean;
|
|
539
|
+
}
|
|
540
|
+
| {
|
|
541
|
+
mode: Exclude<TMDataGridEditMode, "draft">;
|
|
542
|
+
/** Only `"draft"`'s `submitAll` ever calls it - see the other branch. */
|
|
543
|
+
onCommitDrafts?: never;
|
|
544
|
+
/** Confirmed entry rows exist only under `"draft"` - see there. */
|
|
545
|
+
newRowsSticky?: never;
|
|
546
|
+
}
|
|
547
|
+
);
|
|
550
548
|
|
|
551
549
|
export type UseTMDataGridOptions<TData extends RowData> = Omit<
|
|
552
550
|
TableOptions<TMDataGridFeatures, TData>,
|
|
553
551
|
"features"
|
|
554
552
|
> &
|
|
555
|
-
|
|
553
|
+
(
|
|
554
|
+
| { editing?: undefined }
|
|
555
|
+
| {
|
|
556
|
+
/** Turns editing on. See {@link TMDataGridEditingOptions}. */
|
|
557
|
+
editing: TMDataGridEditingOptions<TData>;
|
|
558
|
+
/**
|
|
559
|
+
* Required once `editing` is set: the forms are keyed by row id and
|
|
560
|
+
* live outside the DOM, and the index fallback points at a different
|
|
561
|
+
* record after any sort.
|
|
562
|
+
*/
|
|
563
|
+
getRowId: NonNullable<
|
|
564
|
+
TableOptions<TMDataGridFeatures, TData>["getRowId"]
|
|
565
|
+
>;
|
|
566
|
+
}
|
|
567
|
+
) & {
|
|
556
568
|
/**
|
|
557
569
|
* Restore and persist table state across mounts. Two keys, because the two
|
|
558
570
|
* kinds of state have different lifetimes - see {@link TMDataGridPersistence}.
|
|
@@ -772,9 +784,9 @@ export type UseTMDataGridOptions<TData extends RowData> = Omit<
|
|
|
772
784
|
* Defaults to 160.
|
|
773
785
|
*
|
|
774
786
|
* An estimate, not a height: every mounted row is measured, so the real one
|
|
775
|
-
* takes over as soon as the panel is on screen. It keeps the scrollbar
|
|
776
|
-
* for panels that open off screen
|
|
777
|
-
*
|
|
787
|
+
* takes over as soon as the panel is on screen. It keeps the scrollbar
|
|
788
|
+
* accurate for panels that open off screen, such as restored `expanded`
|
|
789
|
+
* state. An approximate value is enough.
|
|
778
790
|
*/
|
|
779
791
|
renderDetailsEstHeight?: number;
|
|
780
792
|
/**
|
|
@@ -807,6 +819,26 @@ type TMDataGridColumnDef<TData extends RowData> = ColumnDef<
|
|
|
807
819
|
* request for one. Cleared here, so a grouped grid is a tree until a column
|
|
808
820
|
* says otherwise - `aggregationFn: "sum"` on the column that wants it.
|
|
809
821
|
*/
|
|
822
|
+
/**
|
|
823
|
+
* Drops the control lanes' entries from a visibility map.
|
|
824
|
+
*
|
|
825
|
+
* They are all `enableHiding: false`, but TanStack applies `columnVisibility`
|
|
826
|
+
* regardless - the option only gates `toggleVisibility` - so a stale `false`
|
|
827
|
+
* would hide a lane nothing in the grid can bring back: restored from storage
|
|
828
|
+
* written before 2.1 (when the checkbox lane was still hideable), or passed in
|
|
829
|
+
* `initialState`. The tree column is not scrubbed; its entry is the grid's own,
|
|
830
|
+
* written after this.
|
|
831
|
+
*/
|
|
832
|
+
function withoutControlColumnVisibility(
|
|
833
|
+
visibility: Record<string, boolean>,
|
|
834
|
+
): Record<string, boolean> {
|
|
835
|
+
const scrubbed = { ...visibility };
|
|
836
|
+
for (const id of Object.keys(scrubbed)) {
|
|
837
|
+
if (isControlColumn(id)) delete scrubbed[id];
|
|
838
|
+
}
|
|
839
|
+
return scrubbed;
|
|
840
|
+
}
|
|
841
|
+
|
|
810
842
|
function withTMDataGridDefaults<TData extends RowData>(
|
|
811
843
|
columns: ReadonlyArray<TMDataGridColumnDef<TData>>,
|
|
812
844
|
): Array<TMDataGridColumnDef<TData>> {
|
|
@@ -850,19 +882,16 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
850
882
|
onHighlightedRowChange,
|
|
851
883
|
cellSelection,
|
|
852
884
|
onFocusedCellChange,
|
|
853
|
-
|
|
854
|
-
rowValidators,
|
|
855
|
-
isRowEditable,
|
|
856
|
-
onEditCommit,
|
|
857
|
-
onEditCommitBatch,
|
|
858
|
-
newRowDefaults,
|
|
859
|
-
onRowAdd,
|
|
860
|
-
onRowDelete,
|
|
885
|
+
editing,
|
|
861
886
|
renderDetails,
|
|
862
887
|
renderDetailsEstHeight = DEFAULT_DETAILS_EST_HEIGHT,
|
|
863
888
|
overscan = DEFAULT_OVERSCAN,
|
|
864
889
|
...options
|
|
865
890
|
}: UseTMDataGridOptions<TData>): TMDataGridApi<TData> {
|
|
891
|
+
// The one place `editing` is unpacked - the engine and the flags keep their
|
|
892
|
+
// own vocabulary (`editMode`, `onEditCommit`), so the mapping lives here.
|
|
893
|
+
const editMode = editing?.mode;
|
|
894
|
+
|
|
866
895
|
// Derived up here, rather than just before the return, because the rest of the
|
|
867
896
|
// hook needs `selectColumn` - one place decides what each mode means.
|
|
868
897
|
//
|
|
@@ -877,7 +906,7 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
877
906
|
selectionMode,
|
|
878
907
|
showSelectedBackground,
|
|
879
908
|
cellSelection,
|
|
880
|
-
|
|
909
|
+
editing,
|
|
881
910
|
});
|
|
882
911
|
|
|
883
912
|
// Resolved on the override's identity, so a module-scope dictionary costs one
|
|
@@ -891,12 +920,15 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
891
920
|
// `renderDetails` has nothing for it to open.
|
|
892
921
|
const detailsColumnEnabled = renderDetails !== undefined;
|
|
893
922
|
// Row mode's Save sits at the end of the row - the lane is its chrome. It
|
|
894
|
-
// also appears wherever the trash can has somewhere to report to
|
|
923
|
+
// also appears wherever the trash can has somewhere to report to, and
|
|
924
|
+
// always under draft mode, where it is the change marker and the per-row
|
|
925
|
+
// revert - with or without `onCommitDrafts`, since the per-row `submitAll`
|
|
926
|
+
// fallback is a first-class configuration.
|
|
895
927
|
const editColumnEnabled =
|
|
896
|
-
|
|
897
|
-
(
|
|
898
|
-
|
|
899
|
-
|
|
928
|
+
editing !== undefined &&
|
|
929
|
+
(editing.mode === "row" ||
|
|
930
|
+
editing.mode === "draft" ||
|
|
931
|
+
editing.onRowDelete !== undefined);
|
|
900
932
|
|
|
901
933
|
// The generated lanes bake `meta.label` into their definitions, so the memo
|
|
902
934
|
// depends on the strings rather than on the labels object - a fresh
|
|
@@ -907,6 +939,9 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
907
939
|
const editColumnLabel = labels.editColumnLabel;
|
|
908
940
|
const rowNumberColumnLabel = labels.rowNumberColumnLabel;
|
|
909
941
|
const rowNumbersEnabled = features.rowNumbers;
|
|
942
|
+
// Draft mode's lane holds three controls (state icon, undo, trash) where
|
|
943
|
+
// the other modes hold two - it gets the wider track.
|
|
944
|
+
const editIsDraftMode = editing?.mode === "draft";
|
|
910
945
|
|
|
911
946
|
const columns = useMemo(() => {
|
|
912
947
|
const base = withTMDataGridDefaults<TData>(
|
|
@@ -936,7 +971,9 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
936
971
|
: []),
|
|
937
972
|
...base,
|
|
938
973
|
// Last and pinned right - the row's Save belongs at the end of the row.
|
|
939
|
-
...(editColumnEnabled
|
|
974
|
+
...(editColumnEnabled
|
|
975
|
+
? [createEditColumn<TData>(editColumnLabel, editIsDraftMode)]
|
|
976
|
+
: []),
|
|
940
977
|
];
|
|
941
978
|
}, [
|
|
942
979
|
options.columns,
|
|
@@ -945,6 +982,7 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
945
982
|
detailsColumnEnabled,
|
|
946
983
|
groupColumnEnabled,
|
|
947
984
|
editColumnEnabled,
|
|
985
|
+
editIsDraftMode,
|
|
948
986
|
rowNumberColumnLabel,
|
|
949
987
|
selectColumnLabel,
|
|
950
988
|
groupColumnLabel,
|
|
@@ -1008,8 +1046,10 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
1008
1046
|
...options.initialState,
|
|
1009
1047
|
...persistedState,
|
|
1010
1048
|
columnVisibility: {
|
|
1011
|
-
...
|
|
1012
|
-
|
|
1049
|
+
...withoutControlColumnVisibility({
|
|
1050
|
+
...options.initialState?.columnVisibility,
|
|
1051
|
+
...persistedState.columnVisibility,
|
|
1052
|
+
}),
|
|
1013
1053
|
// Last word, because the tree column's visibility is not a user setting
|
|
1014
1054
|
// - it tracks the grouping state. See the effect below.
|
|
1015
1055
|
...(groupColumnEnabled
|
|
@@ -1064,24 +1104,26 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
1064
1104
|
editContextRef.current = {
|
|
1065
1105
|
table: table as unknown as TMDataGridTable<TMDataGridRowData>,
|
|
1066
1106
|
editMode: editMode ?? "cell",
|
|
1067
|
-
rowValidators,
|
|
1068
|
-
isRowEditable:
|
|
1107
|
+
rowValidators: editing?.rowValidators,
|
|
1108
|
+
isRowEditable:
|
|
1109
|
+
editing?.isRowEditable as TMDataGridEditEngineContext["isRowEditable"],
|
|
1069
1110
|
onEditCommit:
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1111
|
+
editing?.onCommit as TMDataGridEditEngineContext["onEditCommit"],
|
|
1112
|
+
onEditCommitDrafts:
|
|
1113
|
+
editing?.onCommitDrafts as TMDataGridEditEngineContext["onEditCommitDrafts"],
|
|
1073
1114
|
newRowDefaults:
|
|
1074
|
-
newRowDefaults as TMDataGridEditEngineContext["newRowDefaults"],
|
|
1075
|
-
onRowAdd: onRowAdd as TMDataGridEditEngineContext["onRowAdd"],
|
|
1076
|
-
onRowDelete:
|
|
1115
|
+
editing?.newRowDefaults as TMDataGridEditEngineContext["newRowDefaults"],
|
|
1116
|
+
onRowAdd: editing?.onRowAdd as TMDataGridEditEngineContext["onRowAdd"],
|
|
1117
|
+
onRowDelete:
|
|
1118
|
+
editing?.onRowDelete as TMDataGridEditEngineContext["onRowDelete"],
|
|
1077
1119
|
};
|
|
1078
1120
|
const [edit] = useState(() =>
|
|
1079
1121
|
createEditEngine(() => editContextRef.current),
|
|
1080
1122
|
);
|
|
1081
1123
|
|
|
1082
1124
|
// Switching modes mid-flight drops every draft: the policies disagree about
|
|
1083
|
-
// what an open form means, and carrying one across is how a
|
|
1084
|
-
// silently commits under "cell".
|
|
1125
|
+
// what an open form means, and carrying one across is how a draft parked
|
|
1126
|
+
// under "draft" silently commits under "cell".
|
|
1085
1127
|
const previousEditModeRef = useRef(editMode);
|
|
1086
1128
|
useEffect(() => {
|
|
1087
1129
|
if (previousEditModeRef.current === editMode) return;
|
|
@@ -1092,9 +1134,9 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
1092
1134
|
// Editing without stable ids points every draft at whatever record slides
|
|
1093
1135
|
// into that index after a sort. Loud, once, in development.
|
|
1094
1136
|
useEffect(() => {
|
|
1095
|
-
if (
|
|
1137
|
+
if (editing !== undefined && options.getRowId === undefined) {
|
|
1096
1138
|
console.error(
|
|
1097
|
-
"TMDataGrid:
|
|
1139
|
+
"TMDataGrid: editing requires getRowId - drafts are keyed by row id, and the index fallback names a different record after any sort or filter.",
|
|
1098
1140
|
);
|
|
1099
1141
|
}
|
|
1100
1142
|
// The check is a mount-time contract, not something to re-run per render.
|
|
@@ -1240,9 +1282,9 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
1240
1282
|
),
|
|
1241
1283
|
setCellRange: (range) =>
|
|
1242
1284
|
setState((prev) =>
|
|
1243
|
-
// Same guard as above, and it
|
|
1244
|
-
// corner on every mouse move, and most of those land on the cell
|
|
1245
|
-
// range already ends at.
|
|
1285
|
+
// Same guard as above, and it matters more here: a drag publishes a
|
|
1286
|
+
// new corner on every mouse move, and most of those land on the cell
|
|
1287
|
+
// the range already ends at.
|
|
1246
1288
|
isSameCell(prev.cellRange?.anchor ?? null, range?.anchor ?? null) &&
|
|
1247
1289
|
isSameCell(prev.cellRange?.focus ?? null, range?.focus ?? null)
|
|
1248
1290
|
? prev
|
|
@@ -1302,7 +1344,7 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
1302
1344
|
const grouping = [...(initial?.grouping ?? [])];
|
|
1303
1345
|
table.setGrouping(grouping);
|
|
1304
1346
|
table.setColumnVisibility({
|
|
1305
|
-
...initial?.columnVisibility,
|
|
1347
|
+
...withoutControlColumnVisibility({ ...initial?.columnVisibility }),
|
|
1306
1348
|
// The tree lane's visibility tracks the grouping, never the user.
|
|
1307
1349
|
...(groupColumnEnabled ? { [GROUP_COLUMN_ID]: grouping.length > 0 } : {}),
|
|
1308
1350
|
});
|
|
@@ -1333,8 +1375,8 @@ export function useTMDataGrid<TData extends RowData>({
|
|
|
1333
1375
|
const resetSettings = useCallback(() => resetSettingsRef.current(), []);
|
|
1334
1376
|
|
|
1335
1377
|
// Filled in by `TMDataGrid.Table` on every render, because only the body
|
|
1336
|
-
// holds the virtualizer and the current view.
|
|
1337
|
-
// mounted,
|
|
1378
|
+
// holds the virtualizer and the current view. Returns `false` until one is
|
|
1379
|
+
// mounted, since there is nothing to scroll before then.
|
|
1338
1380
|
const scrollerRef = useRef<TMDataGridScroller>(() => false);
|
|
1339
1381
|
const scrollToRow = useCallback(
|
|
1340
1382
|
(args: TMDataGridScrollToRowArgs) => scrollerRef.current(args),
|