diff --git a/packages/table-core/src/core/rows/coreRowsFeature.utils.ts b/packages/table-core/src/core/rows/coreRowsFeature.utils.ts index cf41cf7d67..6891f48f7c 100644 --- a/packages/table-core/src/core/rows/coreRowsFeature.utils.ts +++ b/packages/table-core/src/core/rows/coreRowsFeature.utils.ts @@ -188,8 +188,8 @@ export function table_getMaxSubRowDepth< /** * Looks up this row's direct parent, if it has one. * - * Parent lookup searches the pre-pagination row model so parent relationships - * are available even when the parent is not on the current page. + * Parent lookup prefers the core row model for structural parents, then falls + * back to the pre-pagination row model for generated parent rows. * * @example * ```ts @@ -200,7 +200,14 @@ export function row_getParentRow< TFeatures extends TableFeatures, TData extends RowData, >(row: Row) { - return row.parentId ? row.table.getRow(row.parentId, true) : undefined + if (!row.parentId) { + return undefined + } + + return ( + row.table.getCoreRowModel().rowsById[row.parentId] ?? + row.table.getRow(row.parentId, true) + ) } /** diff --git a/packages/table-core/tests/implementation/features/column-filtering/createFilteredRowModel.test.ts b/packages/table-core/tests/implementation/features/column-filtering/createFilteredRowModel.test.ts index 455a34f509..a6b3d1427d 100644 --- a/packages/table-core/tests/implementation/features/column-filtering/createFilteredRowModel.test.ts +++ b/packages/table-core/tests/implementation/features/column-filtering/createFilteredRowModel.test.ts @@ -80,6 +80,55 @@ const rowNames = (rows: Array<{ original: { name: string } }>) => rows.map((row) => row.original.name) describe('createFilteredRowModel', () => { + it('allows a filter function to inspect structural parent rows', () => { + const parentAwareFilter: FilterFn = ( + row, + columnId, + filterValue, + ) => { + const parent = row.getParentRow() + return [row, parent] + .filter((candidate) => candidate !== undefined) + .some((candidate) => + String(candidate.getValue(columnId)) + .toLowerCase() + .includes(String(filterValue).toLowerCase()), + ) + } + const table = constructTable({ + features, + columns: [ + { + accessorKey: 'name', + id: 'name', + filterFn: parentAwareFilter, + }, + ], + data: [ + { name: 'parent', subRows: [{ name: 'child' }] }, + { name: 'other', subRows: [{ name: 'nested' }] }, + ], + getSubRows: (row) => row.subRows, + initialState: { + columnFilters: [{ id: 'name', value: 'parent' }], + }, + }) + + expect(() => table.getFilteredRowModel()).not.toThrow() + expect(rowNames(table.getFilteredRowModel().flatRows).sort()).toEqual([ + 'child', + 'parent', + ]) + + table.setColumnFilters([{ id: 'name', value: 'other' }]) + + expect(() => table.getFilteredRowModel()).not.toThrow() + expect(rowNames(table.getFilteredRowModel().flatRows).sort()).toEqual([ + 'nested', + 'other', + ]) + }) + it('should assign display indexes in filtered row order', () => { const table = constructTable({ features,