diff --git a/docs/guide/headers.md b/docs/guide/headers.md index 54167acb23..622fd831e8 100644 --- a/docs/guide/headers.md +++ b/docs/guide/headers.md @@ -58,6 +58,7 @@ There are a few properties on `header` objects that are only useful if the heade - `isPlaceholder`: A boolean flag that is true if the header is a placeholder header. Placeholder headers fill the rows above a shallow leaf column's real header so that every header row accounts for every visible column. Render them as empty cells to keep the header grid aligned, or use `header.rowSpan` to merge each placeholder chain into one vertically spanning header cell. - `placeholderId`: The unique identifier for the placeholder header. - `subHeaders`: The array of sub/child headers that belong to this header. Will be empty if the header is a leaf header. +- `getLeafHeaders()`: The leaf headers nested under this header, in left-to-right order. Group and placeholder headers are excluded, so a leaf header returns just itself. Use `table.getFlatHeaders()` if you need every header, group headers included. > [!NOTE] > `header.index` refers to its index within the header group (row of headers), i.e. its position from left to right. It is not the same as `header.depth`, which refers to the header group "row index". diff --git a/packages/table-core/src/core/headers/coreHeadersFeature.utils.ts b/packages/table-core/src/core/headers/coreHeadersFeature.utils.ts index 2bf5f108e6..8f07bae4c4 100644 --- a/packages/table-core/src/core/headers/coreHeadersFeature.utils.ts +++ b/packages/table-core/src/core/headers/coreHeadersFeature.utils.ts @@ -19,18 +19,21 @@ function collectLeafHeaders< header: Header_Header, leafHeaders: Array>, ): void { + if (!header.subHeaders.length) { + leafHeaders.push(header as Header) + return + } + for (let i = 0; i < header.subHeaders.length; i++) { collectLeafHeaders(header.subHeaders[i]!, leafHeaders) } - - leafHeaders.push(header as Header) } /** * Walks a header tree and collects all descendant leaf headers. * - * The header itself is included after its descendants, matching the recursive - * shape used by nested header groups. + * Parent/group headers are skipped, so the result is one header per leaf column + * in left-to-right order. A header that is itself a leaf returns just itself. * * @example * ```ts diff --git a/packages/table-core/tests/unit/core/headers/coreHeadersFeature.utils.test.ts b/packages/table-core/tests/unit/core/headers/coreHeadersFeature.utils.test.ts index 394c0dae1d..4400925657 100644 --- a/packages/table-core/tests/unit/core/headers/coreHeadersFeature.utils.test.ts +++ b/packages/table-core/tests/unit/core/headers/coreHeadersFeature.utils.test.ts @@ -300,7 +300,7 @@ describe('header rowSpan for uneven column trees', () => { }) describe('header_getLeafHeaders', () => { - it('should collect descendant leaf headers before the header itself', () => { + it('should collect descendant leaf headers without the group header itself', () => { const table = makeTable() const groupHeader = table_getHeaderGroups(table)[0]!.headers.find( (header) => header.column.id === 'group', @@ -308,11 +308,7 @@ describe('header_getLeafHeaders', () => { const leafHeaders = header_getLeafHeaders(groupHeader) - expect(leafHeaders.map((header) => header.column.id)).toEqual([ - 'a', - 'b', - 'group', - ]) + expect(leafHeaders.map((header) => header.column.id)).toEqual(['a', 'b']) }) it('should return only itself for a leaf header', () => { @@ -324,7 +320,7 @@ describe('header_getLeafHeaders', () => { expect(header_getLeafHeaders(leafHeader)).toEqual([leafHeader]) }) - it('should preserve descendant-first identity across three levels', () => { + it('should skip intermediate group headers across three levels', () => { const deepColumns: Array> = [ { id: 'outer', @@ -346,18 +342,12 @@ describe('header_getLeafHeaders', () => { }) const headerGroups = table_getHeaderGroups(table) const outer = headerGroups[0]!.headers[0]! - const inner = headerGroups[1]!.headers[0]! const [a, b] = headerGroups[2]!.headers const leafHeaders = header_getLeafHeaders(outer) - expect(leafHeaders.map((header) => header.column.id)).toEqual([ - 'a', - 'b', - 'inner', - 'outer', - ]) - expect(leafHeaders).toEqual([a, b, inner, outer]) + expect(leafHeaders.map((header) => header.column.id)).toEqual(['a', 'b']) + expect(leafHeaders).toEqual([a, b]) }) }) @@ -379,6 +369,15 @@ describe('table_getLeafHeaders', () => { const table = makeTable() const ids = table_getLeafHeaders(table).map((header) => header.column.id) - expect(ids).toEqual(expect.arrayContaining(['a', 'b', 'c'])) + expect(ids).toEqual(['a', 'b', 'c']) + }) + + it('should return the real leaf header instead of its placeholder chain', () => { + const table = makeTable() + const leafHeaders = table_getLeafHeaders(table) + + expect(leafHeaders.every((header) => !header.isPlaceholder)).toBe(true) + // Real leaf headers keep the plain column id; placeholders do not. + expect(leafHeaders.map((header) => header.id)).toEqual(['a', 'b', 'c']) }) })