diff --git a/.changeset/eleven-dingos-drum.md b/.changeset/eleven-dingos-drum.md new file mode 100644 index 0000000000..40323d3633 --- /dev/null +++ b/.changeset/eleven-dingos-drum.md @@ -0,0 +1,5 @@ +--- +'@tanstack/table-core': patch +--- + +fix: toggleAllRowsSelected to respect row selection rules diff --git a/packages/table-core/src/features/RowSelection.ts b/packages/table-core/src/features/RowSelection.ts index e5fddaba9d..1ed45f4798 100644 --- a/packages/table-core/src/features/RowSelection.ts +++ b/packages/table-core/src/features/RowSelection.ts @@ -244,7 +244,10 @@ export const RowSelection: TableFeature = { rowSelection[row.id] = true }) } else { - preGroupedFlatRows.forEach((row) => { + preGroupedFlatRows.forEach(row => { + if (!row.getCanSelect()) { + return + } delete rowSelection[row.id] }) } diff --git a/packages/table-core/tests/RowSelection.test.ts b/packages/table-core/tests/RowSelection.test.ts index 266bf27806..af3e7af494 100644 --- a/packages/table-core/tests/RowSelection.test.ts +++ b/packages/table-core/tests/RowSelection.test.ts @@ -320,4 +320,74 @@ describe('RowSelection', () => { expect(result).toEqual('some') }) }) + + describe('toggleAllRowsSelected', () => { + it('should respect enableRowSelection when selecting all rows', () => { + const data = makeData(5) + const columns = generateColumns(data) + + let rowSelection: Record = {} + + const table = createTable({ + enableRowSelection: row => row.index !== 2, // Row at index 2 cannot be selected + onStateChange: updater => { + const newState = + typeof updater === 'function' ? updater(table.getState()) : updater + rowSelection = newState.rowSelection + }, + renderFallbackValue: '', + data, + get state() { + return { rowSelection } + }, + columns, + getCoreRowModel: getCoreRowModel(), + }) + + table.toggleAllRowsSelected(true) + + expect(rowSelection['0']).toBe(true) + expect(rowSelection['1']).toBe(true) + expect(rowSelection['2']).toBeUndefined() // Row 2 should not be selected + expect(rowSelection['3']).toBe(true) + expect(rowSelection['4']).toBe(true) + }) + + it('should respect enableRowSelection when deselecting all rows', () => { + const data = makeData(5) + const columns = generateColumns(data) + + let rowSelection: Record = { + '0': true, + '1': true, + '2': true, // This row was somehow selected (maybe rules changed) + '3': true, + '4': true, + } + + const table = createTable({ + enableRowSelection: row => row.index !== 2, // Row at index 2 cannot be selected + onStateChange: updater => { + const newState = + typeof updater === 'function' ? updater(table.getState()) : updater + rowSelection = newState.rowSelection + }, + renderFallbackValue: '', + data, + get state() { + return { rowSelection } + }, + columns, + getCoreRowModel: getCoreRowModel(), + }) + + table.toggleAllRowsSelected(false) + + expect(rowSelection['0']).toBeUndefined() + expect(rowSelection['1']).toBeUndefined() + expect(rowSelection['2']).toBe(true) // Row 2 should remain selected since it can't be deselected + expect(rowSelection['3']).toBeUndefined() + expect(rowSelection['4']).toBeUndefined() + }) + }) })