@tanstack/table-core 9.0.0-beta.73 → 9.0.0-beta.75

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.
@@ -92,7 +92,11 @@ function constructTable(tableOptions) {
92
92
  const reactiveState = externalAtom ? externalAtom.get() : table.baseAtoms[key].get();
93
93
  if (externalAtom) return reactiveState;
94
94
  const controlledState = options.state;
95
- return controlledState && hasOwn(controlledState, key) ? controlledState[key] : reactiveState;
95
+ if (controlledState && hasOwn(controlledState, key)) {
96
+ const controlledValue = controlledState[key];
97
+ return controlledValue === void 0 ? table.initialState[key] : controlledValue;
98
+ }
99
+ return reactiveState;
96
100
  }, { debugName: `table/atoms/${key}` });
97
101
  }
98
102
  table_syncExternalStateToBaseAtoms(table);
@@ -27,7 +27,8 @@ function table_syncExternalStateToBaseAtoms(table, capturedState, compare = (cur
27
27
  if (state) for (const key in state) {
28
28
  const baseAtom = table.baseAtoms[key];
29
29
  if (!baseAtom) continue;
30
- const externalState = state[key];
30
+ const rawExternalState = state[key];
31
+ const externalState = rawExternalState === void 0 ? table.initialState[key] : rawExternalState;
31
32
  if (!compare(table._reactivity.untrack(() => baseAtom.get()), externalState)) baseAtom.set(() => externalState);
32
33
  }
33
34
  });
@@ -85,7 +85,8 @@ const rowSelectionFeature = {
85
85
  memoDeps: () => [
86
86
  table.atoms.rowSelection?.get(),
87
87
  table.getFilteredRowModel(),
88
- table.options.enableRowSelection
88
+ table.options.enableRowSelection,
89
+ table.options.enableSubRowSelection
89
90
  ]
90
91
  },
91
92
  table_getIsAllPageRowsSelected: {
@@ -93,7 +94,8 @@ const rowSelectionFeature = {
93
94
  memoDeps: () => [
94
95
  table.atoms.rowSelection?.get(),
95
96
  table.getPaginatedRowModel(),
96
- table.options.enableRowSelection
97
+ table.options.enableRowSelection,
98
+ table.options.enableSubRowSelection
97
99
  ]
98
100
  },
99
101
  table_getIsSomeRowsSelected: {
@@ -5,7 +5,7 @@ import { TableFeatures } from "../../types/TableFeatures.js";
5
5
  //#region src/features/row-selection/rowSelectionFeature.types.d.ts
6
6
  type RowSelectionState = Record<string, true>;
7
7
  /**
8
- * Controls how toggling a row affects its descendants.
8
+ * Controls how toggling a row affects its descendants and ancestors.
9
9
  */
10
10
  interface ToggleSelectedOptions {
11
11
  /**
@@ -13,6 +13,17 @@ interface ToggleSelectedOptions {
13
13
  * `true`.
14
14
  */
15
15
  selectChildren?: boolean;
16
+ /**
17
+ * Whether ancestor row ids should be removed from the selection when this
18
+ * row is deselected. Useful after a parent cascade wrote the parent id into
19
+ * state and a child is later deselected. Defaults to `false`.
20
+ *
21
+ * Ancestor ids are removed even when the ancestor itself cannot be selected.
22
+ * Like the other targeted deselection paths, pruning is not gated by
23
+ * `enableRowSelection`; only the bulk select-all paths preserve
24
+ * non-selectable rows.
25
+ */
26
+ deselectParents?: boolean;
16
27
  }
17
28
  interface TableState_RowSelection {
18
29
  rowSelection: RowSelectionState;
@@ -39,7 +50,8 @@ interface TableOptions_RowSelection<in out TFeatures extends TableFeatures, in o
39
50
  * Controls whether selecting a parent row also selects its subRows.
40
51
  *
41
52
  * Provide a predicate to decide per row. This is most useful with expanding or
42
- * grouping features and defaults to `true`.
53
+ * grouping features and defaults to `true`. Select-all and the all-selected
54
+ * getters also skip descendants of parents that block sub-row selection.
43
55
  */
44
56
  enableSubRowSelection?: boolean | ((row: Row<TFeatures, TData>) => boolean);
45
57
  /**
@@ -115,10 +127,12 @@ interface Table_RowSelection<in out TFeatures extends TableFeatures, in out TDat
115
127
  getSelectedRowIds: () => Array<string>;
116
128
  /**
117
129
  * Checks whether every selectable row on the current page is selected.
130
+ * Sub-rows whose ancestors block sub-row selection are ignored.
118
131
  */
119
132
  getIsAllPageRowsSelected: () => boolean;
120
133
  /**
121
134
  * Checks whether every selectable filtered row is selected.
135
+ * Sub-rows whose ancestors block sub-row selection are ignored.
122
136
  */
123
137
  getIsAllRowsSelected: () => boolean;
124
138
  /**
@@ -163,6 +177,9 @@ interface Table_RowSelection<in out TFeatures extends TableFeatures, in out TDat
163
177
  }) => void;
164
178
  /**
165
179
  * Selects/deselects all rows in the table.
180
+ *
181
+ * Deselecting keeps rows that cannot be selected in the selection map unless
182
+ * `opts.deselectAll` is `true`.
166
183
  */
167
184
  toggleAllRowsSelected: (value?: boolean, opts?: {
168
185
  deselectAll?: boolean;
@@ -46,7 +46,10 @@ declare function table_resetRowSelection<TFeatures extends TableFeatures, TData
46
46
  * Selects or deselects every selectable row before grouping.
47
47
  *
48
48
  * Omitting `value` toggles based on `table_getIsAllRowsSelected(table)`.
49
- * Deselecting removes matching ids from the existing selection map.
49
+ * Selecting skips sub-rows whose ancestors block descent via
50
+ * `enableSubRowSelection`. Deselecting removes matching selectable ids from the
51
+ * existing selection map; rows that cannot be selected keep their selection
52
+ * unless `opts.deselectAll` is `true`.
50
53
  *
51
54
  * @example
52
55
  * ```ts
@@ -143,7 +146,8 @@ declare function table_getSelectedRowIds<TFeatures extends TableFeatures, TData
143
146
  * Checks whether every selectable filtered row is selected.
144
147
  *
145
148
  * The result is false when there are no filtered rows or when selection state is
146
- * empty.
149
+ * empty. Sub-rows whose ancestors block descent via `enableSubRowSelection` are
150
+ * ignored, matching the rows that `table_toggleAllRowsSelected` selects.
147
151
  *
148
152
  * @example
149
153
  * ```ts
@@ -154,7 +158,8 @@ declare function table_getIsAllRowsSelected<TFeatures extends TableFeatures, TDa
154
158
  /**
155
159
  * Checks whether every selectable row on the current page is selected.
156
160
  *
157
- * Non-selectable rows are ignored for this calculation.
161
+ * Non-selectable rows are ignored for this calculation, as are sub-rows whose
162
+ * ancestors block descent via `enableSubRowSelection`.
158
163
  *
159
164
  * @example
160
165
  * ```ts
@@ -211,7 +216,8 @@ declare function table_getToggleAllPageRowsSelectedHandler<TFeatures extends Tab
211
216
  *
212
217
  * Omitting `value` toggles the row. Child rows are selected recursively unless
213
218
  * `opts.selectChildren` is `false`, sub-row selection is disabled, or the row
214
- * only supports single selection.
219
+ * only supports single selection. Pass `deselectParents: true` to also remove
220
+ * ancestor row ids from the selection when this row is deselected.
215
221
  *
216
222
  * @example
217
223
  * ```ts
@@ -219,7 +225,7 @@ declare function table_getToggleAllPageRowsSelectedHandler<TFeatures extends Tab
219
225
  * row_toggleSelected(row, true)
220
226
  * row_toggleSelected(row, false)
221
227
  * row_toggleSelected(row, true, { selectChildren: false })
222
- * row_toggleSelected(row, false, { selectChildren: false })
228
+ * row_toggleSelected(row, false, { deselectParents: true })
223
229
  * ```
224
230
  */
225
231
  declare function row_toggleSelected<TFeatures extends TableFeatures, TData extends RowData>(row: Row<TFeatures, TData>, value?: boolean, opts?: ToggleSelectedOptions): void;
@@ -299,7 +305,8 @@ declare function row_getCanMultiSelect<TFeatures extends TableFeatures, TData ex
299
305
  * `event.target.checked`. Shift events select or deselect the inclusive range
300
306
  * from the most recent selectable row handled by this table. Pass
301
307
  * `selectChildren: false` to limit changes to rows explicitly present in the
302
- * display-order interval.
308
+ * display-order interval, and `deselectParents: true` to remove ancestor row
309
+ * ids from the selection when rows are deselected.
303
310
  *
304
311
  * @example
305
312
  * ```ts
@@ -49,7 +49,10 @@ function table_resetRowSelection(table, defaultState) {
49
49
  * Selects or deselects every selectable row before grouping.
50
50
  *
51
51
  * Omitting `value` toggles based on `table_getIsAllRowsSelected(table)`.
52
- * Deselecting removes matching ids from the existing selection map.
52
+ * Selecting skips sub-rows whose ancestors block descent via
53
+ * `enableSubRowSelection`. Deselecting removes matching selectable ids from the
54
+ * existing selection map; rows that cannot be selected keep their selection
55
+ * unless `opts.deselectAll` is `true`.
53
56
  *
54
57
  * @example
55
58
  * ```ts
@@ -63,11 +66,13 @@ function table_toggleAllRowsSelected(table, value, opts) {
63
66
  if (opts?.deselectAll && !value) return makeObjectMap();
64
67
  const rowSelection = Object.assign(makeObjectMap(), old);
65
68
  const preGroupedFlatRows = table.getPreGroupedRowModel().flatRows;
66
- if (value) preGroupedFlatRows.forEach((row) => {
67
- if (row_getCanSelect(row)) rowSelection[row.id] = true;
68
- });
69
- else preGroupedFlatRows.forEach((row) => {
70
- delete rowSelection[row.id];
69
+ if (value) {
70
+ const subtreeCache = /* @__PURE__ */ new Map();
71
+ preGroupedFlatRows.forEach((row) => {
72
+ if (isRowSelectableInSelectAll(row, subtreeCache)) rowSelection[row.id] = true;
73
+ });
74
+ } else preGroupedFlatRows.forEach((row) => {
75
+ if (row_getCanSelect(row)) delete rowSelection[row.id];
71
76
  });
72
77
  return rowSelection;
73
78
  });
@@ -90,7 +95,7 @@ function table_toggleAllPageRowsSelected(table, value, opts) {
90
95
  if (opts?.deselectAll && !resolvedValue) return makeObjectMap();
91
96
  const rowSelection = Object.assign(makeObjectMap(), old);
92
97
  table.getRowModel().rows.forEach((row) => {
93
- mutateRowIsSelected(rowSelection, row.id, resolvedValue, true, table);
98
+ mutateRowIsSelected(rowSelection, row.id, resolvedValue, true, table, true);
94
99
  });
95
100
  return rowSelection;
96
101
  });
@@ -184,7 +189,8 @@ function table_getSelectedRowIds(table) {
184
189
  * Checks whether every selectable filtered row is selected.
185
190
  *
186
191
  * The result is false when there are no filtered rows or when selection state is
187
- * empty.
192
+ * empty. Sub-rows whose ancestors block descent via `enableSubRowSelection` are
193
+ * ignored, matching the rows that `table_toggleAllRowsSelected` selects.
188
194
  *
189
195
  * @example
190
196
  * ```ts
@@ -196,14 +202,16 @@ function table_getIsAllRowsSelected(table) {
196
202
  const rowSelection = table.atoms.rowSelection?.get() ?? {};
197
203
  let isAllRowsSelected = Boolean(preGroupedFlatRows.length && Object.keys(rowSelection).length);
198
204
  if (isAllRowsSelected) {
199
- if (preGroupedFlatRows.some((row) => row_getCanSelect(row) && !isRowSelected(row, rowSelection))) isAllRowsSelected = false;
205
+ const subtreeCache = /* @__PURE__ */ new Map();
206
+ if (preGroupedFlatRows.some((row) => !isRowSelected(row, rowSelection) && isRowSelectableInSelectAll(row, subtreeCache))) isAllRowsSelected = false;
200
207
  }
201
208
  return isAllRowsSelected;
202
209
  }
203
210
  /**
204
211
  * Checks whether every selectable row on the current page is selected.
205
212
  *
206
- * Non-selectable rows are ignored for this calculation.
213
+ * Non-selectable rows are ignored for this calculation, as are sub-rows whose
214
+ * ancestors block descent via `enableSubRowSelection`.
207
215
  *
208
216
  * @example
209
217
  * ```ts
@@ -211,11 +219,17 @@ function table_getIsAllRowsSelected(table) {
211
219
  * ```
212
220
  */
213
221
  function table_getIsAllPageRowsSelected(table) {
214
- const paginationFlatRows = table.getPaginatedRowModel().flatRows.filter((row) => row_getCanSelect(row));
222
+ const paginationFlatRows = table.getPaginatedRowModel().flatRows;
215
223
  const rowSelection = table.atoms.rowSelection?.get() ?? {};
216
- let isAllPageRowsSelected = !!paginationFlatRows.length;
217
- if (isAllPageRowsSelected && paginationFlatRows.some((row) => !isRowSelected(row, rowSelection))) isAllPageRowsSelected = false;
218
- return isAllPageRowsSelected;
224
+ const subtreeCache = /* @__PURE__ */ new Map();
225
+ let sawSelectableRow = false;
226
+ for (let i = 0; i < paginationFlatRows.length; i++) {
227
+ const row = paginationFlatRows[i];
228
+ if (!isRowSelected(row, rowSelection)) {
229
+ if (isRowSelectableInSelectAll(row, subtreeCache)) return false;
230
+ } else if (!sawSelectableRow && isRowSelectableInSelectAll(row, subtreeCache)) sawSelectableRow = true;
231
+ }
232
+ return sawSelectableRow;
219
233
  }
220
234
  /**
221
235
  * Checks whether at least one row id is selected.
@@ -278,7 +292,8 @@ function table_getToggleAllPageRowsSelectedHandler(table) {
278
292
  *
279
293
  * Omitting `value` toggles the row. Child rows are selected recursively unless
280
294
  * `opts.selectChildren` is `false`, sub-row selection is disabled, or the row
281
- * only supports single selection.
295
+ * only supports single selection. Pass `deselectParents: true` to also remove
296
+ * ancestor row ids from the selection when this row is deselected.
282
297
  *
283
298
  * @example
284
299
  * ```ts
@@ -286,7 +301,7 @@ function table_getToggleAllPageRowsSelectedHandler(table) {
286
301
  * row_toggleSelected(row, true)
287
302
  * row_toggleSelected(row, false)
288
303
  * row_toggleSelected(row, true, { selectChildren: false })
289
- * row_toggleSelected(row, false, { selectChildren: false })
304
+ * row_toggleSelected(row, false, { deselectParents: true })
290
305
  * ```
291
306
  */
292
307
  function row_toggleSelected(row, value, opts) {
@@ -295,6 +310,7 @@ function row_toggleSelected(row, value, opts) {
295
310
  value = typeof value !== "undefined" ? value : !isSelected;
296
311
  const rowSelection = Object.assign(makeObjectMap(), old);
297
312
  mutateRowIsSelected(rowSelection, row.id, value, (opts?.selectChildren ?? true) && row_getCanMultiSelect(row), row.table);
313
+ if (!value && opts?.deselectParents) pruneAncestorRowIds(rowSelection, row);
298
314
  return rowSelection;
299
315
  });
300
316
  }
@@ -392,7 +408,8 @@ function row_getCanMultiSelect(row) {
392
408
  * `event.target.checked`. Shift events select or deselect the inclusive range
393
409
  * from the most recent selectable row handled by this table. Pass
394
410
  * `selectChildren: false` to limit changes to rows explicitly present in the
395
- * display-order interval.
411
+ * display-order interval, and `deselectParents: true` to remove ancestor row
412
+ * ids from the selection when rows are deselected.
396
413
  *
397
414
  * @example
398
415
  * ```ts
@@ -407,7 +424,7 @@ function row_getToggleSelectedHandler(row, opts) {
407
424
  const table = row.table;
408
425
  const checked = event.target.checked;
409
426
  const anchorId = table._lastSelectedRowId;
410
- if (!(table.options.enableRowRangeSelection !== false && anchorId !== null && row_getCanMultiSelect(row) && (table.options.isRowRangeSelectionEvent?.(e) ?? false)) || !selectRowRange(row, anchorId, checked, opts?.selectChildren ?? true)) row_toggleSelected(row, checked, opts);
427
+ if (!(table.options.enableRowRangeSelection !== false && anchorId !== null && row_getCanMultiSelect(row) && (table.options.isRowRangeSelectionEvent?.(e) ?? false)) || !selectRowRange(row, anchorId, checked, opts)) row_toggleSelected(row, checked, opts);
411
428
  table._lastSelectedRowId = row.id;
412
429
  };
413
430
  }
@@ -422,7 +439,8 @@ function row_getToggleSelectedHandler(row, opts) {
422
439
  * selection updater; non-selectable and non-multi-selectable rows are skipped.
423
440
  * Returns `false` when the interaction should fall back to an ordinary toggle.
424
441
  */
425
- function selectRowRange(row, anchorId, value, includeChildren) {
442
+ function selectRowRange(row, anchorId, value, opts) {
443
+ const includeChildren = opts?.selectChildren ?? true;
426
444
  const table = row.table;
427
445
  const rows = table.getRowsInDisplayOrder();
428
446
  const anchorRow = table.getPrePaginatedRowModel().rowsById[anchorId] ?? table.getCoreRowModel().rowsById[anchorId];
@@ -440,19 +458,65 @@ function selectRowRange(row, anchorId, value, includeChildren) {
440
458
  const rangeRow = rows[index];
441
459
  if (!row_getCanSelect(rangeRow) || !row_getCanMultiSelect(rangeRow)) continue;
442
460
  mutateRowIsSelected(rowSelection, rangeRow.id, value, includeChildren, table);
461
+ if (!value && opts?.deselectParents) pruneAncestorRowIds(rowSelection, rangeRow);
443
462
  }
444
463
  return rowSelection;
445
464
  });
446
465
  return true;
447
466
  }
448
- const mutateRowIsSelected = (rowSelection, rowId, value, includeChildren, table) => {
467
+ function mutateRowIsSelected(rowSelection, rowId, value, includeChildren, table, respectCanSelectOnDeselect) {
449
468
  const row = table.getRow(rowId, true);
450
469
  if (value) {
451
470
  if (!row_getCanMultiSelect(row)) Object.keys(rowSelection).forEach((key) => delete rowSelection[key]);
452
471
  if (row_getCanSelect(row)) rowSelection[rowId] = true;
453
- } else delete rowSelection[rowId];
454
- if (includeChildren && row.subRows.length && row_getCanSelectSubRows(row)) row.subRows.forEach((r) => mutateRowIsSelected(rowSelection, r.id, value, includeChildren, table));
455
- };
472
+ } else if (!respectCanSelectOnDeselect || row_getCanSelect(row)) delete rowSelection[rowId];
473
+ if (includeChildren && row.subRows.length && row_getCanSelectSubRows(row)) row.subRows.forEach((r) => mutateRowIsSelected(rowSelection, r.id, value, includeChildren, table, respectCanSelectOnDeselect));
474
+ }
475
+ /**
476
+ * Returns whether a select-all cascade can reach this row: the row itself is
477
+ * selectable and no ancestor blocks descent via `enableSubRowSelection`.
478
+ *
479
+ * `subtreeCache` memoizes the per-ancestor verdict for one select-all pass, so
480
+ * ancestor chains shared by sibling rows are only walked (and the
481
+ * `enableSubRowSelection` predicate only invoked) once per unique ancestor.
482
+ */
483
+ function isRowSelectableInSelectAll(row, subtreeCache) {
484
+ if (!row_getCanSelect(row)) return false;
485
+ const table = row.table;
486
+ if (table.options.enableSubRowSelection === true) return true;
487
+ const parentId = row.parentId;
488
+ if (parentId === void 0) return true;
489
+ const cached = subtreeCache.get(parentId);
490
+ if (cached !== void 0) return cached;
491
+ const rowsById = table.getCoreRowModel().rowsById;
492
+ const visited = [];
493
+ let selectable = true;
494
+ let currentId = parentId;
495
+ while (currentId !== void 0) {
496
+ const known = subtreeCache.get(currentId);
497
+ if (known !== void 0) {
498
+ selectable = known;
499
+ break;
500
+ }
501
+ visited.push(currentId);
502
+ const parent = rowsById[currentId] ?? table.getRow(currentId, true);
503
+ if (!row_getCanSelectSubRows(parent)) {
504
+ selectable = false;
505
+ break;
506
+ }
507
+ currentId = parent.parentId;
508
+ }
509
+ visited.forEach((id) => subtreeCache.set(id, selectable));
510
+ return selectable;
511
+ }
512
+ function pruneAncestorRowIds(rowSelection, row) {
513
+ const rowsById = row.table.getCoreRowModel().rowsById;
514
+ let parentId = row.parentId;
515
+ while (parentId !== void 0) {
516
+ delete rowSelection[parentId];
517
+ parentId = (rowsById[parentId] ?? row.table.getRow(parentId, true)).parentId;
518
+ }
519
+ }
456
520
  function selectRowsRecursively(rows, rowSelection, selectedFlatRows, selectedRowsById) {
457
521
  const result = [];
458
522
  for (let i = 0; i < rows.length; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/table-core",
3
- "version": "9.0.0-beta.73",
3
+ "version": "9.0.0-beta.75",
4
4
  "description": "Headless UI for building powerful tables & datagrids for TS/JS.",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.73',
9
+ library_version: '9.0.0-beta.75',
10
10
  }
11
11
  requires: ['core', 'table-features']
12
12
  sources:
@@ -5,7 +5,7 @@ description: >
5
5
  metadata:
6
6
  type: sub-skill
7
7
  library: '@tanstack/table-core'
8
- library_version: '9.0.0-beta.73'
8
+ library_version: '9.0.0-beta.75'
9
9
  requires: ['core', 'table-features']
10
10
  sources:
11
11
  - 'TanStack/table:packages/table-core/src/index.ts'
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.73',
9
+ library_version: '9.0.0-beta.75',
10
10
  }
11
11
  requires: ['core', 'table-features']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.73',
9
+ library_version: '9.0.0-beta.75',
10
10
  }
11
11
  requires: ['core', 'table-features']
12
12
  sources:
@@ -5,7 +5,7 @@ description: >
5
5
  metadata:
6
6
  type: sub-skill
7
7
  library: '@tanstack/table-core'
8
- library_version: '9.0.0-beta.73'
8
+ library_version: '9.0.0-beta.75'
9
9
  requires: ['core', 'table-features']
10
10
  sources:
11
11
  - 'TanStack/table:docs/guide/row-models.md'
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.73',
9
+ library_version: '9.0.0-beta.75',
10
10
  }
11
11
  requires: ['core', 'table-features', 'column-filtering']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.73',
9
+ library_version: '9.0.0-beta.75',
10
10
  }
11
11
  requires: ['core', 'table-features', 'client-vs-server']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.73',
9
+ library_version: '9.0.0-beta.75',
10
10
  }
11
11
  requires: ['core', 'table-features']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.73',
9
+ library_version: '9.0.0-beta.75',
10
10
  }
11
11
  requires: ['core', 'table-features', 'column-sizing']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.73',
9
+ library_version: '9.0.0-beta.75',
10
10
  }
11
11
  requires: ['core', 'table-features', 'column-sizing']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.73',
9
+ library_version: '9.0.0-beta.75',
10
10
  }
11
11
  requires: ['core', 'table-features']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.73',
9
+ library_version: '9.0.0-beta.75',
10
10
  }
11
11
  requires: ['core', 'table-features']
12
12
  sources:
@@ -5,7 +5,7 @@ description: >
5
5
  metadata:
6
6
  type: core
7
7
  library: '@tanstack/table-core'
8
- library_version: '9.0.0-beta.73'
8
+ library_version: '9.0.0-beta.75'
9
9
  sources:
10
10
  - 'TanStack/table:docs/overview.md'
11
11
  - 'TanStack/table:docs/guide/tables.md'
@@ -5,7 +5,7 @@ description: >
5
5
  metadata:
6
6
  type: sub-skill
7
7
  library: '@tanstack/table-core'
8
- library_version: '9.0.0-beta.73'
8
+ library_version: '9.0.0-beta.75'
9
9
  requires: ['core', 'table-features', 'typescript']
10
10
  sources:
11
11
  - 'TanStack/table:docs/framework/react/guide/custom-features.md'
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.73',
9
+ library_version: '9.0.0-beta.75',
10
10
  }
11
11
  requires: ['core', 'table-features', 'client-vs-server']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.73',
9
+ library_version: '9.0.0-beta.75',
10
10
  }
11
11
  requires: ['core', 'table-features', 'client-vs-server', 'column-filtering']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.73',
9
+ library_version: '9.0.0-beta.75',
10
10
  }
11
11
  requires: ['core', 'table-features', 'client-vs-server']
12
12
  sources:
@@ -5,7 +5,7 @@ description: >
5
5
  metadata:
6
6
  type: lifecycle
7
7
  library: '@tanstack/table-core'
8
- library_version: '9.0.0-beta.73'
8
+ library_version: '9.0.0-beta.75'
9
9
  requires: ['core', 'table-features', 'typescript']
10
10
  sources:
11
11
  - 'TanStack/table:docs/framework/react/guide/migrating.md'
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.73',
9
+ library_version: '9.0.0-beta.75',
10
10
  }
11
11
  requires: ['core', 'table-features', 'client-vs-server']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.73',
9
+ library_version: '9.0.0-beta.75',
10
10
  }
11
11
  requires: ['core', 'table-features']
12
12
  sources:
@@ -1,12 +1,12 @@
1
1
  ---
2
2
  name: row-selection
3
3
  description: >
4
- Maintain rowSelection ID state with stable getRowId, single, multi, subrow, and Shift-range rules, selected row models, handler anchors, and manual-pagination semantics. Load when implementing getToggleSelectedHandler, enableRowRangeSelection, selectChildren, or selected IDs that outlive loaded Row objects.
4
+ Maintain rowSelection ID state with stable getRowId, single, multi, subrow, and Shift-range rules, selected row models, handler anchors, and manual-pagination semantics. Load when implementing getToggleSelectedHandler, enableRowRangeSelection, selectChildren, deselectParents, or selected IDs that outlive loaded Row objects.
5
5
  metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.73',
9
+ library_version: '9.0.0-beta.75',
10
10
  }
11
11
  requires: ['core', 'table-features']
12
12
  sources:
@@ -65,6 +65,20 @@ export function getDisplayedRowsOnlyHandler(row: Row<typeof features, Person>) {
65
65
 
66
66
  The default `selectChildren: true` recursively changes selectable descendants of parents encountered in the range. Set it to `false` when collapsed descendants outside the display-order interval must remain unchanged.
67
67
 
68
+ ### Prune stale parent ids on child deselection
69
+
70
+ ```ts
71
+ export function getPruningHandler(row: Row<typeof features, Person>) {
72
+ return row.getToggleSelectedHandler({ deselectParents: true })
73
+ }
74
+ ```
75
+
76
+ Selecting a parent cascades its id plus selectable descendant ids into state, but deselecting a child later leaves the parent id behind by default (some tables treat state ids as literal selections, e.g. with `selectChildren: false`). The default `deselectParents: false` preserves that; set it to `true` so deselecting any row also deletes every ancestor id, keeping `row.getIsSelected()` honest for parents. Applies to `toggleSelected` and both plain and Shift-range handler paths.
77
+
78
+ ### Select-all honors sub-row selection rules
79
+
80
+ With `enableSubRowSelection: false` (or a per-row predicate), `table.toggleAllRowsSelected()` skips descendants of blocking parents, and `getIsAllRowsSelected()`/`getIsAllPageRowsSelected()` exclude those descendants from the all-selected computation, so the header checkbox still reads checked. Deselect-all skips rows whose `enableRowSelection` resolves false, preserving their selection; use `toggleAllRowsSelected(false, { deselectAll: true })` or `resetRowSelection(true)` to clear everything including disabled and out-of-model ids.
81
+
68
82
  ## Common Mistakes
69
83
 
70
84
  ### [HIGH] Expecting selection to clean itself
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.73',
9
+ library_version: '9.0.0-beta.75',
10
10
  }
11
11
  requires: ['core', 'table-features', 'client-vs-server']
12
12
  sources:
@@ -5,7 +5,7 @@ description: >
5
5
  metadata:
6
6
  type: sub-skill
7
7
  library: '@tanstack/table-core'
8
- library_version: '9.0.0-beta.73'
8
+ library_version: '9.0.0-beta.75'
9
9
  requires: ['core']
10
10
  sources:
11
11
  - 'TanStack/table:docs/guide/row-models.md'
@@ -5,7 +5,7 @@ description: >
5
5
  metadata:
6
6
  type: sub-skill
7
7
  library: '@tanstack/table-core'
8
- library_version: '9.0.0-beta.73'
8
+ library_version: '9.0.0-beta.75'
9
9
  requires: ['core', 'table-features']
10
10
  sources:
11
11
  - 'TanStack/table:docs/guide/helpers.md'