@tanstack/table-core 9.0.0-beta.23 → 9.0.0-beta.27

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.
Files changed (58) hide show
  1. package/README.md +1 -0
  2. package/dist/features/column-ordering/columnOrderingFeature.cjs +2 -1
  3. package/dist/features/column-ordering/columnOrderingFeature.cjs.map +1 -1
  4. package/dist/features/column-ordering/columnOrderingFeature.js +2 -1
  5. package/dist/features/column-ordering/columnOrderingFeature.js.map +1 -1
  6. package/dist/features/column-pinning/columnPinningFeature.cjs +24 -12
  7. package/dist/features/column-pinning/columnPinningFeature.cjs.map +1 -1
  8. package/dist/features/column-pinning/columnPinningFeature.js +24 -12
  9. package/dist/features/column-pinning/columnPinningFeature.js.map +1 -1
  10. package/dist/features/column-resizing/columnResizingFeature.utils.cjs +62 -24
  11. package/dist/features/column-resizing/columnResizingFeature.utils.cjs.map +1 -1
  12. package/dist/features/column-resizing/columnResizingFeature.utils.js +62 -24
  13. package/dist/features/column-resizing/columnResizingFeature.utils.js.map +1 -1
  14. package/dist/features/column-sizing/columnSizingFeature.cjs +35 -45
  15. package/dist/features/column-sizing/columnSizingFeature.cjs.map +1 -1
  16. package/dist/features/column-sizing/columnSizingFeature.js +36 -46
  17. package/dist/features/column-sizing/columnSizingFeature.js.map +1 -1
  18. package/dist/features/column-sizing/columnSizingFeature.types.d.cts +38 -1
  19. package/dist/features/column-sizing/columnSizingFeature.types.d.ts +38 -1
  20. package/dist/features/column-sizing/columnSizingFeature.utils.cjs +49 -10
  21. package/dist/features/column-sizing/columnSizingFeature.utils.cjs.map +1 -1
  22. package/dist/features/column-sizing/columnSizingFeature.utils.d.cts +18 -4
  23. package/dist/features/column-sizing/columnSizingFeature.utils.d.ts +18 -4
  24. package/dist/features/column-sizing/columnSizingFeature.utils.js +49 -11
  25. package/dist/features/column-sizing/columnSizingFeature.utils.js.map +1 -1
  26. package/dist/features/column-visibility/columnVisibilityFeature.cjs +8 -4
  27. package/dist/features/column-visibility/columnVisibilityFeature.cjs.map +1 -1
  28. package/dist/features/column-visibility/columnVisibilityFeature.js +8 -4
  29. package/dist/features/column-visibility/columnVisibilityFeature.js.map +1 -1
  30. package/dist/features/column-visibility/columnVisibilityFeature.utils.cjs +3 -2
  31. package/dist/features/column-visibility/columnVisibilityFeature.utils.cjs.map +1 -1
  32. package/dist/features/column-visibility/columnVisibilityFeature.utils.js +3 -2
  33. package/dist/features/column-visibility/columnVisibilityFeature.utils.js.map +1 -1
  34. package/dist/features/row-selection/rowSelectionFeature.cjs +22 -2
  35. package/dist/features/row-selection/rowSelectionFeature.cjs.map +1 -1
  36. package/dist/features/row-selection/rowSelectionFeature.js +22 -2
  37. package/dist/features/row-selection/rowSelectionFeature.js.map +1 -1
  38. package/dist/features/row-selection/rowSelectionFeature.utils.cjs +6 -6
  39. package/dist/features/row-selection/rowSelectionFeature.utils.cjs.map +1 -1
  40. package/dist/features/row-selection/rowSelectionFeature.utils.js +6 -6
  41. package/dist/features/row-selection/rowSelectionFeature.utils.js.map +1 -1
  42. package/dist/index.d.cts +2 -2
  43. package/dist/index.d.ts +2 -2
  44. package/dist/static-functions.cjs +1 -0
  45. package/dist/static-functions.d.cts +2 -2
  46. package/dist/static-functions.d.ts +2 -2
  47. package/dist/static-functions.js +2 -2
  48. package/package.json +1 -1
  49. package/src/features/column-ordering/columnOrderingFeature.ts +1 -0
  50. package/src/features/column-pinning/columnPinningFeature.ts +12 -0
  51. package/src/features/column-resizing/columnResizingFeature.utils.ts +96 -44
  52. package/src/features/column-sizing/columnSizingFeature.ts +18 -18
  53. package/src/features/column-sizing/columnSizingFeature.types.ts +39 -0
  54. package/src/features/column-sizing/columnSizingFeature.utils.ts +94 -39
  55. package/src/features/column-visibility/columnVisibilityFeature.ts +4 -0
  56. package/src/features/column-visibility/columnVisibilityFeature.utils.ts +4 -2
  57. package/src/features/row-selection/rowSelectionFeature.ts +10 -0
  58. package/src/features/row-selection/rowSelectionFeature.utils.ts +11 -10
@@ -130,60 +130,112 @@ export function header_getResizeHandler<
130
130
  return
131
131
  }
132
132
 
133
- table_setColumnResizing(column.table, (old) => {
134
- const deltaDirection =
135
- column.table.options.columnResizeDirection === 'rtl' ? -1 : 1
136
- const deltaOffset =
137
- (clientXPos - (old.startOffset ?? 0)) * deltaDirection
138
- const startSize = old.startSize ?? 0
139
- const deltaPercentage = Math.max(
140
- startSize > 0 ? deltaOffset / startSize : 0,
141
- -0.999999,
142
- )
143
-
144
- old.columnSizingStart.forEach(([columnId, headerSize]) => {
145
- newColumnSizing[columnId] =
146
- Math.round(
147
- Math.max(
148
- headerSize > 0
149
- ? headerSize + headerSize * deltaPercentage
150
- : deltaOffset / old.columnSizingStart.length,
151
- 0,
152
- ) * 100,
153
- ) / 100
133
+ const table = column.table
134
+ const isCommit =
135
+ table.options.columnResizeMode === 'onChange' || eventType === 'end'
136
+
137
+ // one notification flush per tick instead of two
138
+ table._reactivity.batch(() => {
139
+ table_setColumnResizing(table, (old) => {
140
+ const deltaDirection =
141
+ table.options.columnResizeDirection === 'rtl' ? -1 : 1
142
+ const deltaOffset =
143
+ (clientXPos - (old.startOffset ?? 0)) * deltaDirection
144
+ const startSize = old.startSize ?? 0
145
+ const deltaPercentage = Math.max(
146
+ startSize > 0 ? deltaOffset / startSize : 0,
147
+ -0.999999,
148
+ )
149
+
150
+ // new sizes are only read at commit and are recomputed from
151
+ // absolute positions each time, so skip them on onEnd-mode moves
152
+ if (isCommit) {
153
+ const columnSizingStart = old.columnSizingStart
154
+ for (let i = 0; i < columnSizingStart.length; i++) {
155
+ const entry = columnSizingStart[i]!
156
+ const headerSize = entry[1]
157
+ newColumnSizing[entry[0]] =
158
+ Math.round(
159
+ Math.max(
160
+ headerSize > 0
161
+ ? headerSize + headerSize * deltaPercentage
162
+ : deltaOffset / columnSizingStart.length,
163
+ 0,
164
+ ) * 100,
165
+ ) / 100
166
+ }
167
+ }
168
+
169
+ return {
170
+ ...old,
171
+ deltaOffset,
172
+ deltaPercentage,
173
+ }
154
174
  })
155
175
 
156
- return {
157
- ...old,
158
- deltaOffset,
159
- deltaPercentage,
176
+ if (isCommit) {
177
+ table_setColumnSizing(table, (old) =>
178
+ Object.assign(makeObjectMap<number>(), old, newColumnSizing),
179
+ )
160
180
  }
161
181
  })
182
+ }
162
183
 
163
- if (
164
- column.table.options.columnResizeMode === 'onChange' ||
165
- eventType === 'end'
166
- ) {
167
- table_setColumnSizing(column.table, (old) =>
168
- Object.assign(makeObjectMap<number>(), old, newColumnSizing),
169
- )
184
+ // Pointer devices can report at several times the display refresh rate,
185
+ // and every update between frames is overwritten by the next one. Apply
186
+ // the first move of a frame immediately, then coalesce the rest into one
187
+ // update per animation frame.
188
+ let moveRafId: number | null = null
189
+ let hasPendingMove = false
190
+ let latestMoveX: number | undefined
191
+
192
+ const flushMove = () => {
193
+ if (hasPendingMove) {
194
+ hasPendingMove = false
195
+ updateOffset('move', latestMoveX)
196
+ moveRafId = requestAnimationFrame(flushMove)
197
+ } else {
198
+ moveRafId = null
170
199
  }
171
200
  }
172
201
 
173
- const onMove = (clientXPos?: number) => updateOffset('move', clientXPos)
202
+ const onMove = (clientXPos?: number) => {
203
+ latestMoveX = clientXPos
204
+ if (typeof requestAnimationFrame !== 'function') {
205
+ updateOffset('move', clientXPos)
206
+ return
207
+ }
208
+ if (moveRafId !== null) {
209
+ hasPendingMove = true
210
+ return
211
+ }
212
+ updateOffset('move', clientXPos)
213
+ moveRafId = requestAnimationFrame(flushMove)
214
+ }
174
215
 
175
216
  const onEnd = (clientXPos?: number) => {
176
- updateOffset('end', clientXPos)
177
-
178
- table_setColumnResizing(column.table, (old) => ({
179
- ...old,
180
- isResizingColumn: false,
181
- startOffset: null,
182
- startSize: null,
183
- deltaOffset: null,
184
- deltaPercentage: null,
185
- columnSizingStart: [],
186
- }))
217
+ if (moveRafId !== null) {
218
+ cancelAnimationFrame(moveRafId)
219
+ moveRafId = null
220
+ hasPendingMove = false
221
+ }
222
+
223
+ // batch the 'end' commit and the reset into one notification flush
224
+ column.table._reactivity.batch(() => {
225
+ // touchend events carry no touch position, so fall back to the last
226
+ // observed move position for the final commit
227
+ updateOffset('end', clientXPos ?? latestMoveX)
228
+
229
+ table_setColumnResizing(column.table, (old) => ({
230
+ ...old,
231
+ isResizingColumn: false,
232
+ startOffset: null,
233
+ startSize: null,
234
+ deltaOffset: null,
235
+ deltaPercentage: null,
236
+ columnSizingStart: [],
237
+ }))
238
+ })
187
239
  }
188
240
 
189
241
  const contextDocument =
@@ -13,6 +13,7 @@ import {
13
13
  header_getSize,
14
14
  header_getStart,
15
15
  table_getCenterTotalSize,
16
+ table_getColumnOffsets,
16
17
  table_getLeftTotalSize,
17
18
  table_getRightTotalSize,
18
19
  table_getTotalSize,
@@ -51,27 +52,13 @@ export const columnSizingFeature: TableFeature = {
51
52
  table.atoms.columnSizing?.get()?.[column.id], // just this column's size state
52
53
  ],
53
54
  },
55
+ // O(1) lookups into the memoized table-level offsets, so no per-column
56
+ // memos here
54
57
  column_getStart: {
55
58
  fn: (column, position) => column_getStart(column, position),
56
- memoDeps: (column, position) => [
57
- position,
58
- table.options.columns,
59
- table.atoms.columnSizing?.get(),
60
- table.atoms.columnOrder?.get(),
61
- table.atoms.columnPinning?.get(),
62
- table.atoms.columnVisibility?.get(),
63
- ],
64
59
  },
65
60
  column_getAfter: {
66
61
  fn: (column, position) => column_getAfter(column, position),
67
- memoDeps: (column, position) => [
68
- position,
69
- table.options.columns,
70
- table.atoms.columnSizing?.get(),
71
- table.atoms.columnOrder?.get(),
72
- table.atoms.columnPinning?.get(),
73
- table.atoms.columnVisibility?.get(),
74
- ],
75
62
  },
76
63
  column_resetSize: {
77
64
  fn: (column) => column_resetSize(column),
@@ -92,13 +79,14 @@ export const columnSizingFeature: TableFeature = {
92
79
  },
93
80
  header_getStart: {
94
81
  fn: (header) => header_getStart(header),
95
- memoDeps: (header, position) => [
96
- position,
82
+ memoDeps: () => [
97
83
  table.options.columns,
98
84
  table.atoms.columnSizing?.get(),
99
85
  table.atoms.columnOrder?.get(),
100
86
  table.atoms.columnPinning?.get(),
101
87
  table.atoms.columnVisibility?.get(),
88
+ table.atoms.grouping?.get(),
89
+ table.options.groupedColumnMode,
102
90
  ],
103
91
  },
104
92
  })
@@ -106,6 +94,18 @@ export const columnSizingFeature: TableFeature = {
106
94
 
107
95
  constructTableAPIs: (table) => {
108
96
  assignTableAPIs('columnSizingFeature', table, {
97
+ table_getColumnOffsets: {
98
+ fn: () => table_getColumnOffsets(table),
99
+ memoDeps: () => [
100
+ table.options.columns,
101
+ table.atoms.columnSizing?.get(),
102
+ table.atoms.columnOrder?.get(),
103
+ table.atoms.columnPinning?.get(),
104
+ table.atoms.columnVisibility?.get(),
105
+ table.atoms.grouping?.get(),
106
+ table.options.groupedColumnMode,
107
+ ],
108
+ },
109
109
  table_setColumnSizing: {
110
110
  fn: (updater) => table_setColumnSizing(table, updater),
111
111
  },
@@ -7,6 +7,38 @@ export interface TableState_ColumnSizing {
7
7
 
8
8
  export type ColumnSizingState = Record<string, number>
9
9
 
10
+ export interface ColumnOffsets {
11
+ /**
12
+ * Offset from the start edge of the region to each column's start edge,
13
+ * keyed by column id.
14
+ */
15
+ starts: Record<string, number>
16
+ /**
17
+ * Offset from the end edge of the region to each column's end edge, keyed by
18
+ * column id.
19
+ */
20
+ afters: Record<string, number>
21
+ }
22
+
23
+ export interface ColumnOffsetsByPosition {
24
+ /**
25
+ * Offsets across all visible leaf columns, ignoring pinning regions.
26
+ */
27
+ all: ColumnOffsets
28
+ /**
29
+ * Offsets within the center (unpinned) region.
30
+ */
31
+ center: ColumnOffsets
32
+ /**
33
+ * Offsets within the left pinned region.
34
+ */
35
+ left: ColumnOffsets
36
+ /**
37
+ * Offsets within the right pinned region.
38
+ */
39
+ right: ColumnOffsets
40
+ }
41
+
10
42
  export interface TableOptions_ColumnSizing {
11
43
  /**
12
44
  * Called with an updater when committed column sizing state changes. Pair
@@ -26,6 +58,13 @@ export interface Table_ColumnSizing {
26
58
  * Sums the current sizes of visible center-region leaf columns.
27
59
  */
28
60
  getCenterTotalSize: () => number
61
+ /**
62
+ * Returns memoized column offset maps (start and after offsets keyed by
63
+ * column id) for each pinning region plus the full visible leaf column list.
64
+ *
65
+ * Backs `column.getStart()` and `column.getAfter()` with O(1) lookups.
66
+ */
67
+ getColumnOffsets: () => ColumnOffsetsByPosition
29
68
  /**
30
69
  * Sums the current sizes of visible left-pinned leaf columns.
31
70
  */
@@ -4,7 +4,6 @@ import {
4
4
  table_getPinnedVisibleLeafColumns,
5
5
  table_getRightHeaderGroups,
6
6
  } from '../column-pinning/columnPinningFeature.utils'
7
- import { column_getIndex } from '../column-ordering/columnOrderingFeature.utils'
8
7
  import {
9
8
  callMemoOrStaticFn,
10
9
  cloneState,
@@ -17,7 +16,11 @@ import type { TableFeatures } from '../../types/TableFeatures'
17
16
  import type { Table_Internal } from '../../types/Table'
18
17
  import type { Header } from '../../types/Header'
19
18
  import type { Column_Internal } from '../../types/Column'
20
- import type { ColumnSizingState } from './columnSizingFeature.types'
19
+ import type {
20
+ ColumnOffsets,
21
+ ColumnOffsetsByPosition,
22
+ ColumnSizingState,
23
+ } from './columnSizingFeature.types'
21
24
 
22
25
  /**
23
26
  * Creates the default committed column sizing state.
@@ -86,6 +89,85 @@ export function column_getSize<
86
89
  )
87
90
  }
88
91
 
92
+ function buildColumnOffsets<
93
+ TFeatures extends TableFeatures,
94
+ TData extends RowData,
95
+ >(columns: Array<Column_Internal<TFeatures, TData, unknown>>): ColumnOffsets {
96
+ const starts = makeObjectMap<number>()
97
+ const afters = makeObjectMap<number>()
98
+ const sizes = new Array<number>(columns.length)
99
+
100
+ let start = 0
101
+ for (let i = 0; i < columns.length; i++) {
102
+ const column = columns[i]!
103
+ const size = callMemoOrStaticFn(column, 'getSize', column_getSize)
104
+ sizes[i] = size
105
+ starts[column.id] = start
106
+ start += size
107
+ }
108
+
109
+ let after = 0
110
+ for (let i = columns.length - 1; i >= 0; i--) {
111
+ afters[columns[i]!.id] = after
112
+ after += sizes[i]!
113
+ }
114
+
115
+ return { starts, afters }
116
+ }
117
+
118
+ /**
119
+ * Builds start and after offset maps for every visible leaf column, computed
120
+ * once per pinning region plus the full visible list.
121
+ *
122
+ * A single table-level memo of this result backs all `column.getStart()` and
123
+ * `column.getAfter()` calls with O(1) lookups.
124
+ *
125
+ * @example
126
+ * ```ts
127
+ * const offsets = table_getColumnOffsets(table)
128
+ * const leftOffset = offsets.left.starts[column.id]
129
+ * ```
130
+ */
131
+ export function table_getColumnOffsets<
132
+ TFeatures extends TableFeatures,
133
+ TData extends RowData,
134
+ >(table: Table_Internal<TFeatures, TData>): ColumnOffsetsByPosition {
135
+ return {
136
+ all: buildColumnOffsets(
137
+ table_getPinnedVisibleLeafColumns(table) as Array<
138
+ Column_Internal<TFeatures, TData, unknown>
139
+ >,
140
+ ),
141
+ center: buildColumnOffsets(
142
+ table_getPinnedVisibleLeafColumns(table, 'center') as Array<
143
+ Column_Internal<TFeatures, TData, unknown>
144
+ >,
145
+ ),
146
+ left: buildColumnOffsets(
147
+ table_getPinnedVisibleLeafColumns(table, 'left') as Array<
148
+ Column_Internal<TFeatures, TData, unknown>
149
+ >,
150
+ ),
151
+ right: buildColumnOffsets(
152
+ table_getPinnedVisibleLeafColumns(table, 'right') as Array<
153
+ Column_Internal<TFeatures, TData, unknown>
154
+ >,
155
+ ),
156
+ }
157
+ }
158
+
159
+ function toOffsetsKey(
160
+ position: ColumnPinningPosition | 'center' | undefined,
161
+ ): keyof ColumnOffsetsByPosition {
162
+ return position === 'left'
163
+ ? 'left'
164
+ : position === 'right'
165
+ ? 'right'
166
+ : position === 'center'
167
+ ? 'center'
168
+ : 'all' // undefined | false use the full visible list
169
+ }
170
+
89
171
  /**
90
172
  * Computes the offset from the start edge of a pinning region to this column.
91
173
  *
@@ -103,28 +185,14 @@ export function column_getStart<
103
185
  TValue extends CellData = CellData,
104
186
  >(
105
187
  column: Column_Internal<TFeatures, TData, TValue>,
106
- position: ColumnPinningPosition | 'center',
188
+ position?: ColumnPinningPosition | 'center',
107
189
  ): number {
108
- const index = callMemoOrStaticFn(
109
- column,
110
- 'getIndex',
111
- column_getIndex,
112
- position,
113
- )
114
- if (index <= 0) return 0
115
-
116
- const visibleLeafColumns = callMemoOrStaticFn(
190
+ const offsets = callMemoOrStaticFn(
117
191
  column.table,
118
- 'getPinnedVisibleLeafColumns',
119
- table_getPinnedVisibleLeafColumns,
120
- position,
121
- )
122
-
123
- const prevColumn = visibleLeafColumns[index - 1]!
124
- return (
125
- callMemoOrStaticFn(prevColumn, 'getStart', column_getStart, position) +
126
- callMemoOrStaticFn(prevColumn, 'getSize', column_getSize)
192
+ 'getColumnOffsets',
193
+ table_getColumnOffsets,
127
194
  )
195
+ return offsets[toOffsetsKey(position)].starts[column.id] ?? 0
128
196
  }
129
197
 
130
198
  /**
@@ -144,27 +212,14 @@ export function column_getAfter<
144
212
  TValue extends CellData = CellData,
145
213
  >(
146
214
  column: Column_Internal<TFeatures, TData, TValue>,
147
- position: ColumnPinningPosition | 'center',
215
+ position?: ColumnPinningPosition | 'center',
148
216
  ): number {
149
- const visibleLeafColumns = callMemoOrStaticFn(
217
+ const offsets = callMemoOrStaticFn(
150
218
  column.table,
151
- 'getPinnedVisibleLeafColumns',
152
- table_getPinnedVisibleLeafColumns,
153
- position,
154
- )
155
- const index = callMemoOrStaticFn(
156
- column,
157
- 'getIndex',
158
- column_getIndex,
159
- position,
160
- )
161
- if (index < 0 || index >= visibleLeafColumns.length - 1) return 0
162
-
163
- const nextColumn = visibleLeafColumns[index + 1]!
164
- return (
165
- callMemoOrStaticFn(nextColumn, 'getSize', column_getSize) +
166
- callMemoOrStaticFn(nextColumn, 'getAfter', column_getAfter, position)
219
+ 'getColumnOffsets',
220
+ table_getColumnOffsets,
167
221
  )
222
+ return offsets[toOffsetsKey(position)].afters[column.id] ?? 0
168
223
  }
169
224
 
170
225
  /**
@@ -88,7 +88,9 @@ export const columnVisibilityFeature: TableFeature = {
88
88
  memoDeps: () => [
89
89
  table.atoms.columnVisibility?.get(),
90
90
  table.atoms.columnOrder?.get(),
91
+ table.atoms.grouping?.get(),
91
92
  table.options.columns,
93
+ table.options.groupedColumnMode,
92
94
  ],
93
95
  },
94
96
  table_getVisibleLeafColumns: {
@@ -96,7 +98,9 @@ export const columnVisibilityFeature: TableFeature = {
96
98
  memoDeps: () => [
97
99
  table.atoms.columnVisibility?.get(),
98
100
  table.atoms.columnOrder?.get(),
101
+ table.atoms.grouping?.get(),
99
102
  table.options.columns,
103
+ table.options.groupedColumnMode,
100
104
  ],
101
105
  },
102
106
  table_setColumnVisibility: {
@@ -72,6 +72,9 @@ export function column_getIsVisible<
72
72
  TData extends RowData,
73
73
  TValue extends CellData = CellData,
74
74
  >(column: Column_Internal<TFeatures, TData, TValue>): boolean {
75
+ const columnVisibility = column.table.atoms.columnVisibility?.get()
76
+ if (!columnVisibility) return true
77
+
75
78
  const childColumns = column.columns
76
79
  if (childColumns.length) {
77
80
  return childColumns.some((childColumn) =>
@@ -79,9 +82,8 @@ export function column_getIsVisible<
79
82
  )
80
83
  }
81
84
 
82
- const columnVisibility = column.table.atoms.columnVisibility?.get()
83
85
  return (
84
- (columnVisibility && hasOwn(columnVisibility, column.id)
86
+ (hasOwn(columnVisibility, column.id)
85
87
  ? columnVisibility[column.id]
86
88
  : undefined) ?? true
87
89
  )
@@ -61,9 +61,19 @@ export const rowSelectionFeature: TableFeature = {
61
61
  },
62
62
  row_getIsSomeSelected: {
63
63
  fn: (row) => row_getIsSomeSelected(row),
64
+ memoDeps: (row) => [
65
+ row.subRows,
66
+ row.table.atoms.rowSelection?.get(),
67
+ row.table.options.enableRowSelection,
68
+ ],
64
69
  },
65
70
  row_getIsAllSubRowsSelected: {
66
71
  fn: (row) => row_getIsAllSubRowsSelected(row),
72
+ memoDeps: (row) => [
73
+ row.subRows,
74
+ row.table.atoms.rowSelection?.get(),
75
+ row.table.options.enableRowSelection,
76
+ ],
67
77
  },
68
78
  row_getCanSelect: {
69
79
  fn: (row) => row_getCanSelect(row),
@@ -416,7 +416,11 @@ export function table_getIsSomePageRowsSelected<
416
416
  return table
417
417
  .getPaginatedRowModel()
418
418
  .flatRows.filter((row) => row_getCanSelect(row))
419
- .some((row) => row_getIsSelected(row) || row_getIsSomeSelected(row))
419
+ .some(
420
+ (row) =>
421
+ row_getIsSelected(row) ||
422
+ callMemoOrStaticFn(row, 'getIsSomeSelected', row_getIsSomeSelected),
423
+ )
420
424
  }
421
425
 
422
426
  /**
@@ -497,10 +501,6 @@ export function row_toggleSelected<
497
501
  table_setRowSelection(row.table, (old) => {
498
502
  value = typeof value !== 'undefined' ? value : !isSelected
499
503
 
500
- if (row_getCanSelect(row) && isSelected === value) {
501
- return old
502
- }
503
-
504
504
  const rowSelection = Object.assign(makeObjectMap<true>(), old)
505
505
 
506
506
  mutateRowIsSelected(
@@ -787,13 +787,15 @@ export function isSubRowSelected<
787
787
 
788
788
  const rowSelection = row.table.atoms.rowSelection?.get() ?? {}
789
789
 
790
- let allChildrenSelected = true
791
790
  let someSelected = false
791
+ let allChildrenSelected = true
792
+
793
+ for (let i = 0; i < row.subRows.length; i++) {
794
+ const subRow = row.subRows[i]!
792
795
 
793
- row.subRows.forEach((subRow) => {
794
796
  // Bail out early if we know both of these
795
797
  if (someSelected && !allChildrenSelected) {
796
- return
798
+ break
797
799
  }
798
800
 
799
801
  if (row_getCanSelect(subRow)) {
@@ -816,8 +818,7 @@ export function isSubRowSelected<
816
818
  allChildrenSelected = false
817
819
  }
818
820
  }
819
- })
821
+ }
820
822
 
821
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
822
823
  return allChildrenSelected ? 'all' : someSelected ? 'some' : false
823
824
  }