@tanstack/table-core 9.0.0-beta.37 → 9.0.0-beta.42
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.
- package/README.md +1 -0
- package/dist/core/headers/buildHeaderGroups.cjs.map +1 -1
- package/dist/core/headers/buildHeaderGroups.d.cts +1 -1
- package/dist/core/headers/buildHeaderGroups.d.ts +1 -1
- package/dist/core/headers/buildHeaderGroups.js.map +1 -1
- package/dist/core/headers/coreHeadersFeature.utils.cjs +7 -7
- package/dist/core/headers/coreHeadersFeature.utils.cjs.map +1 -1
- package/dist/core/headers/coreHeadersFeature.utils.js +7 -7
- package/dist/core/headers/coreHeadersFeature.utils.js.map +1 -1
- package/dist/core/table/coreTablesFeature.utils.cjs +1 -1
- package/dist/core/table/coreTablesFeature.utils.cjs.map +1 -1
- package/dist/core/table/coreTablesFeature.utils.js +1 -1
- package/dist/core/table/coreTablesFeature.utils.js.map +1 -1
- package/dist/features/column-ordering/columnOrderingFeature.types.d.cts +5 -5
- package/dist/features/column-ordering/columnOrderingFeature.types.d.ts +5 -5
- package/dist/features/column-ordering/columnOrderingFeature.utils.cjs +6 -6
- package/dist/features/column-ordering/columnOrderingFeature.utils.cjs.map +1 -1
- package/dist/features/column-ordering/columnOrderingFeature.utils.d.cts +3 -3
- package/dist/features/column-ordering/columnOrderingFeature.utils.d.ts +3 -3
- package/dist/features/column-ordering/columnOrderingFeature.utils.js +6 -6
- package/dist/features/column-ordering/columnOrderingFeature.utils.js.map +1 -1
- package/dist/features/column-pinning/columnPinningFeature.cjs +44 -39
- package/dist/features/column-pinning/columnPinningFeature.cjs.map +1 -1
- package/dist/features/column-pinning/columnPinningFeature.d.cts +6 -1
- package/dist/features/column-pinning/columnPinningFeature.d.ts +6 -1
- package/dist/features/column-pinning/columnPinningFeature.js +45 -40
- package/dist/features/column-pinning/columnPinningFeature.js.map +1 -1
- package/dist/features/column-pinning/columnPinningFeature.types.d.cts +49 -38
- package/dist/features/column-pinning/columnPinningFeature.types.d.ts +49 -38
- package/dist/features/column-pinning/columnPinningFeature.utils.cjs +154 -146
- package/dist/features/column-pinning/columnPinningFeature.utils.cjs.map +1 -1
- package/dist/features/column-pinning/columnPinningFeature.utils.d.cts +81 -73
- package/dist/features/column-pinning/columnPinningFeature.utils.d.ts +81 -73
- package/dist/features/column-pinning/columnPinningFeature.utils.js +141 -133
- package/dist/features/column-pinning/columnPinningFeature.utils.js.map +1 -1
- package/dist/features/column-sizing/columnSizingFeature.cjs +4 -4
- package/dist/features/column-sizing/columnSizingFeature.cjs.map +1 -1
- package/dist/features/column-sizing/columnSizingFeature.js +5 -5
- package/dist/features/column-sizing/columnSizingFeature.js.map +1 -1
- package/dist/features/column-sizing/columnSizingFeature.types.d.cts +18 -12
- package/dist/features/column-sizing/columnSizingFeature.types.d.ts +18 -12
- package/dist/features/column-sizing/columnSizingFeature.utils.cjs +24 -20
- package/dist/features/column-sizing/columnSizingFeature.utils.cjs.map +1 -1
- package/dist/features/column-sizing/columnSizingFeature.utils.d.cts +18 -14
- package/dist/features/column-sizing/columnSizingFeature.utils.d.ts +18 -14
- package/dist/features/column-sizing/columnSizingFeature.utils.js +24 -20
- package/dist/features/column-sizing/columnSizingFeature.utils.js.map +1 -1
- package/dist/features/column-visibility/columnVisibilityFeature.utils.cjs +16 -16
- package/dist/features/column-visibility/columnVisibilityFeature.utils.cjs.map +1 -1
- package/dist/features/column-visibility/columnVisibilityFeature.utils.d.cts +3 -3
- package/dist/features/column-visibility/columnVisibilityFeature.utils.d.ts +3 -3
- package/dist/features/column-visibility/columnVisibilityFeature.utils.js +16 -16
- package/dist/features/column-visibility/columnVisibilityFeature.utils.js.map +1 -1
- package/dist/static-functions.cjs +16 -16
- package/dist/static-functions.d.cts +3 -3
- package/dist/static-functions.d.ts +3 -3
- package/dist/static-functions.js +3 -3
- package/package.json +1 -1
- package/skills/api-not-found/SKILL.md +113 -0
- package/skills/client-vs-server/SKILL.md +164 -0
- package/skills/column-faceting/SKILL.md +91 -0
- package/skills/column-filtering/SKILL.md +82 -0
- package/skills/column-ordering/SKILL.md +75 -0
- package/skills/column-pinning/SKILL.md +89 -0
- package/skills/column-resizing/SKILL.md +91 -0
- package/skills/column-sizing/SKILL.md +72 -0
- package/skills/column-visibility/SKILL.md +75 -0
- package/skills/core/SKILL.md +140 -0
- package/skills/custom-features/SKILL.md +207 -0
- package/skills/expanding/SKILL.md +80 -0
- package/skills/global-filtering/SKILL.md +84 -0
- package/skills/grouping/SKILL.md +50 -394
- package/skills/migrate-v8-to-v9/SKILL.md +230 -390
- package/skills/pagination/SKILL.md +35 -344
- package/skills/row-pinning/SKILL.md +47 -238
- package/skills/row-selection/SKILL.md +39 -351
- package/skills/sorting/SKILL.md +35 -299
- package/skills/table-features/SKILL.md +153 -0
- package/skills/typescript/SKILL.md +126 -0
- package/src/core/headers/buildHeaderGroups.ts +1 -1
- package/src/core/headers/coreHeadersFeature.utils.ts +7 -7
- package/src/core/table/coreTablesFeature.utils.ts +1 -1
- package/src/features/column-ordering/columnOrderingFeature.types.ts +5 -5
- package/src/features/column-ordering/columnOrderingFeature.utils.ts +9 -9
- package/src/features/column-pinning/columnPinningFeature.ts +64 -59
- package/src/features/column-pinning/columnPinningFeature.types.ts +49 -38
- package/src/features/column-pinning/columnPinningFeature.utils.ts +163 -155
- package/src/features/column-sizing/columnSizingFeature.ts +6 -6
- package/src/features/column-sizing/columnSizingFeature.types.ts +18 -12
- package/src/features/column-sizing/columnSizingFeature.utils.ts +31 -27
- package/src/features/column-visibility/columnVisibilityFeature.utils.ts +15 -15
- package/skills/column-definitions/SKILL.md +0 -330
- package/skills/column-layout/SKILL.md +0 -326
- package/skills/column-layout/references/subsystems.md +0 -220
- package/skills/customizing-feature-behavior/SKILL.md +0 -423
- package/skills/filtering/SKILL.md +0 -375
- package/skills/filtering/references/faceting-and-fuzzy.md +0 -218
- package/skills/row-expanding/SKILL.md +0 -356
- package/skills/setup/SKILL.md +0 -390
- package/skills/state-management/SKILL.md +0 -403
package/skills/grouping/SKILL.md
CHANGED
|
@@ -1,443 +1,99 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: grouping
|
|
3
3
|
description: >
|
|
4
|
-
Group rows
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
`getIsAggregated` / `getIsPlaceholder`, the built-in `aggregationFns` registry,
|
|
13
|
-
and the required `rowExpandingFeature` pairing for drill-down UX.
|
|
14
|
-
type: core
|
|
15
|
-
library: tanstack-table
|
|
16
|
-
library_version: '9.0.0-alpha.48'
|
|
17
|
-
requires:
|
|
18
|
-
- state-management
|
|
19
|
-
- customizing-feature-behavior
|
|
4
|
+
Group and aggregate rows with columnGroupingFeature, groupedRowModel, aggregationFns, groupedColumnMode, and manualGrouping. Load for grouped, placeholder, or aggregated cells and grouping interactions with expansion or pagination.
|
|
5
|
+
metadata:
|
|
6
|
+
{
|
|
7
|
+
type: sub-skill,
|
|
8
|
+
library: '@tanstack/table-core',
|
|
9
|
+
library_version: '9.0.0-beta.42',
|
|
10
|
+
}
|
|
11
|
+
requires: ['core', 'table-features', 'client-vs-server']
|
|
20
12
|
sources:
|
|
21
|
-
- TanStack/table:docs/guide/grouping.md
|
|
22
|
-
- TanStack/table:packages/table-core/src/
|
|
23
|
-
- TanStack/table:
|
|
24
|
-
- TanStack/table:examples/react/grouping/src/main.tsx
|
|
13
|
+
- 'TanStack/table:docs/framework/react/guide/grouping.md'
|
|
14
|
+
- 'TanStack/table:packages/table-core/src/features/column-grouping'
|
|
15
|
+
- 'TanStack/table:examples/react/grouping'
|
|
25
16
|
---
|
|
26
17
|
|
|
27
|
-
This skill builds on `
|
|
18
|
+
This skill builds on `core`, `table-features`, and `client-vs-server`. Grouping creates row structure and aggregate values; the renderer chooses grouped-cell UI.
|
|
28
19
|
|
|
29
20
|
## Setup
|
|
30
21
|
|
|
31
|
-
Grouping nearly always pairs with expanding — otherwise grouped rows show aggregates with no way to drill in.
|
|
32
|
-
|
|
33
22
|
```ts
|
|
34
23
|
import {
|
|
35
|
-
|
|
24
|
+
aggregationFns,
|
|
36
25
|
columnGroupingFeature,
|
|
37
|
-
rowExpandingFeature,
|
|
38
|
-
rowPaginationFeature,
|
|
39
26
|
createGroupedRowModel,
|
|
40
|
-
|
|
41
|
-
createPaginatedRowModel,
|
|
42
|
-
aggregationFns,
|
|
43
|
-
createColumnHelper,
|
|
44
|
-
constructTable,
|
|
27
|
+
tableFeatures,
|
|
45
28
|
} from '@tanstack/table-core'
|
|
46
|
-
import type { GroupingState } from '@tanstack/table-core'
|
|
47
29
|
|
|
48
|
-
const features = tableFeatures({
|
|
30
|
+
export const features = tableFeatures({
|
|
49
31
|
columnGroupingFeature,
|
|
50
|
-
rowExpandingFeature,
|
|
51
|
-
rowPaginationFeature,
|
|
52
32
|
groupedRowModel: createGroupedRowModel(),
|
|
53
|
-
expandedRowModel: createExpandedRowModel(),
|
|
54
|
-
paginatedRowModel: createPaginatedRowModel(),
|
|
55
33
|
aggregationFns,
|
|
56
34
|
})
|
|
57
|
-
|
|
58
|
-
const columnHelper = createColumnHelper<typeof features, Person>()
|
|
59
|
-
|
|
60
|
-
const columns = columnHelper.columns([
|
|
61
|
-
columnHelper.accessor('firstName', {
|
|
62
|
-
aggregatedCell: () => null,
|
|
63
|
-
enableGrouping: false,
|
|
64
|
-
}),
|
|
65
|
-
columnHelper.accessor('age', { aggregationFn: 'median' }),
|
|
66
|
-
columnHelper.accessor('visits', { aggregationFn: 'sum' }),
|
|
67
|
-
columnHelper.accessor('status', { aggregationFn: 'count' }),
|
|
68
|
-
columnHelper.accessor('progress', { aggregationFn: 'mean' }),
|
|
69
|
-
])
|
|
70
|
-
|
|
71
|
-
const table = constructTable({
|
|
72
|
-
features,
|
|
73
|
-
columns,
|
|
74
|
-
data,
|
|
75
|
-
initialState: { grouping: [] satisfies GroupingState },
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
table.setGrouping(['status'])
|
|
79
35
|
```
|
|
80
36
|
|
|
81
37
|
## Core Patterns
|
|
82
38
|
|
|
83
|
-
### Per-column group toggle + aggregated cell rendering
|
|
84
|
-
|
|
85
|
-
```tsx
|
|
86
|
-
// From examples/react/grouping/src/main.tsx
|
|
87
|
-
{
|
|
88
|
-
headerGroup.headers.map((header) => (
|
|
89
|
-
<th key={header.id}>
|
|
90
|
-
{header.column.getCanGroup() ? (
|
|
91
|
-
<button onClick={header.column.getToggleGroupingHandler()}>
|
|
92
|
-
{header.column.getIsGrouped()
|
|
93
|
-
? `🛑(${header.column.getGroupedIndex()}) `
|
|
94
|
-
: '👊 '}
|
|
95
|
-
</button>
|
|
96
|
-
) : null}
|
|
97
|
-
<table.FlexRender header={header} />
|
|
98
|
-
</th>
|
|
99
|
-
))
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Cell renderer with three branches: grouped, aggregated, normal
|
|
103
|
-
{
|
|
104
|
-
row.getVisibleCells().map((cell) => (
|
|
105
|
-
<td key={cell.id}>
|
|
106
|
-
{cell.getIsGrouped() ? (
|
|
107
|
-
<>
|
|
108
|
-
<button onClick={row.getToggleExpandedHandler()}>
|
|
109
|
-
{row.getIsExpanded() ? '👇' : '👉'}
|
|
110
|
-
</button>{' '}
|
|
111
|
-
<table.FlexRender cell={cell} /> ({row.subRows.length})
|
|
112
|
-
</>
|
|
113
|
-
) : cell.getIsAggregated() ? (
|
|
114
|
-
<table.FlexRender cell={cell} />
|
|
115
|
-
) : cell.getIsPlaceholder() ? null : (
|
|
116
|
-
<table.FlexRender cell={cell} />
|
|
117
|
-
)}
|
|
118
|
-
</td>
|
|
119
|
-
))
|
|
120
|
-
}
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
### Custom `aggregationFn`
|
|
124
|
-
|
|
125
39
|
```ts
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
) => {
|
|
135
|
-
let totalWeight = 0
|
|
136
|
-
let weightedSum = 0
|
|
137
|
-
leafRows.forEach((row) => {
|
|
138
|
-
const v = row.getValue<number>(columnId)
|
|
139
|
-
const w = row.original.weight
|
|
140
|
-
weightedSum += v * w
|
|
141
|
-
totalWeight += w
|
|
142
|
-
})
|
|
143
|
-
return totalWeight === 0 ? 0 : weightedSum / totalWeight
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const customFeatures = tableFeatures({
|
|
147
|
-
columnGroupingFeature,
|
|
148
|
-
rowExpandingFeature,
|
|
149
|
-
groupedRowModel: createGroupedRowModel(),
|
|
150
|
-
expandedRowModel: createExpandedRowModel(),
|
|
151
|
-
aggregationFns: { ...aggregationFns, weightedAverage },
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
const table = constructTable({
|
|
155
|
-
features: customFeatures,
|
|
156
|
-
columns: columnHelper.columns([
|
|
157
|
-
columnHelper.accessor('progress', {
|
|
158
|
-
aggregationFn: 'weightedAverage',
|
|
159
|
-
aggregatedCell: (info) => `${info.getValue<number>().toFixed(1)}%`,
|
|
160
|
-
}),
|
|
161
|
-
]),
|
|
162
|
-
data,
|
|
163
|
-
})
|
|
40
|
+
const options = { groupedColumnMode: 'reorder' as const }
|
|
41
|
+
const mode = cell.getIsGrouped()
|
|
42
|
+
? 'grouped'
|
|
43
|
+
: cell.getIsAggregated()
|
|
44
|
+
? 'aggregated'
|
|
45
|
+
: cell.getIsPlaceholder()
|
|
46
|
+
? 'placeholder'
|
|
47
|
+
: 'value'
|
|
164
48
|
```
|
|
165
49
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
```ts
|
|
169
|
-
columnHelper.accessor('firstName', {
|
|
170
|
-
// group by full name, not just firstName
|
|
171
|
-
getGroupingValue: (row) => `${row.firstName} ${row.lastName}`,
|
|
172
|
-
})
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
### Control grouped-column placement
|
|
176
|
-
|
|
177
|
-
```ts
|
|
178
|
-
const table = constructTable({
|
|
179
|
-
features,
|
|
180
|
-
columns,
|
|
181
|
-
data,
|
|
182
|
-
groupedColumnMode: 'reorder', // default — grouped columns lead
|
|
183
|
-
// groupedColumnMode: 'remove', // hide grouped columns from visible flow
|
|
184
|
-
// groupedColumnMode: false, // keep columnOrder intact
|
|
185
|
-
})
|
|
186
|
-
```
|
|
50
|
+
Render these cell modes deliberately.
|
|
187
51
|
|
|
188
52
|
## Common Mistakes
|
|
189
53
|
|
|
190
|
-
### [HIGH]
|
|
191
|
-
|
|
192
|
-
Wrong:
|
|
193
|
-
|
|
194
|
-
```ts
|
|
195
|
-
// grouped rows show aggregates but can't be expanded
|
|
196
|
-
const features = tableFeatures({
|
|
197
|
-
columnGroupingFeature,
|
|
198
|
-
groupedRowModel: createGroupedRowModel(),
|
|
199
|
-
aggregationFns,
|
|
200
|
-
})
|
|
201
|
-
const table = useTable({ features, columns, data })
|
|
202
|
-
// row.getToggleExpandedHandler() → TS error or undefined
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
Correct:
|
|
206
|
-
|
|
207
|
-
```ts
|
|
208
|
-
import {
|
|
209
|
-
aggregationFns,
|
|
210
|
-
columnGroupingFeature,
|
|
211
|
-
createExpandedRowModel,
|
|
212
|
-
createGroupedRowModel,
|
|
213
|
-
rowExpandingFeature,
|
|
214
|
-
} from '@tanstack/react-table'
|
|
215
|
-
|
|
216
|
-
const features = tableFeatures({
|
|
217
|
-
columnGroupingFeature,
|
|
218
|
-
rowExpandingFeature,
|
|
219
|
-
groupedRowModel: createGroupedRowModel(),
|
|
220
|
-
expandedRowModel: createExpandedRowModel(),
|
|
221
|
-
aggregationFns,
|
|
222
|
-
})
|
|
223
|
-
|
|
224
|
-
const table = useTable({ features, columns, data })
|
|
225
|
-
|
|
226
|
-
// In cell renderer:
|
|
227
|
-
{cell.getIsGrouped() && (
|
|
228
|
-
<button onClick={row.getToggleExpandedHandler()}>
|
|
229
|
-
{row.getIsExpanded() ? '👇' : '👉'} ({row.subRows.length})
|
|
230
|
-
</button>
|
|
231
|
-
)}
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
Without `rowExpandingFeature`, `row.getToggleExpandedHandler` doesn't exist — grouped rows stay collapsed forever.
|
|
235
|
-
|
|
236
|
-
Source: examples/react/grouping/src/main.tsx
|
|
237
|
-
|
|
238
|
-
### [HIGH] Customizing aggregationFns via a v8-style `tableOptions.aggregationFns` option
|
|
54
|
+
### [HIGH] Registering processing without grouping
|
|
239
55
|
|
|
240
|
-
Wrong:
|
|
56
|
+
Wrong: `tableFeatures({ groupedRowModel: createGroupedRowModel() })`
|
|
241
57
|
|
|
242
|
-
|
|
243
|
-
const table = useTable({
|
|
244
|
-
features: tableFeatures({
|
|
245
|
-
columnGroupingFeature,
|
|
246
|
-
groupedRowModel: createGroupedRowModel(),
|
|
247
|
-
aggregationFns,
|
|
248
|
-
}),
|
|
249
|
-
columns, data,
|
|
250
|
-
// @ts-ignore - this property doesn't exist on v9 TableOptions
|
|
251
|
-
aggregationFns: {
|
|
252
|
-
myCustom: (id, leaf, child) => /* ... */,
|
|
253
|
-
},
|
|
254
|
-
})
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
Correct:
|
|
258
|
-
|
|
259
|
-
```ts
|
|
260
|
-
import { aggregationFns, createGroupedRowModel } from '@tanstack/react-table'
|
|
261
|
-
|
|
262
|
-
const features = tableFeatures({
|
|
263
|
-
columnGroupingFeature,
|
|
264
|
-
rowExpandingFeature,
|
|
265
|
-
groupedRowModel: createGroupedRowModel(),
|
|
266
|
-
expandedRowModel: createExpandedRowModel(),
|
|
267
|
-
aggregationFns: {
|
|
268
|
-
...aggregationFns,
|
|
269
|
-
myCustomAggregation: (columnId, leafRows, childRows) => {
|
|
270
|
-
return /* aggregated value */
|
|
271
|
-
},
|
|
272
|
-
},
|
|
273
|
-
})
|
|
274
|
-
|
|
275
|
-
const table = useTable({ features, columns, data })
|
|
276
|
-
|
|
277
|
-
// Then on a column:
|
|
278
|
-
columnHelper.accessor('sales', { aggregationFn: 'myCustomAggregation' })
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
In v9, the aggregation registry is the `aggregationFns` slot on `features`. There is no top-level `tableOptions.aggregationFns`.
|
|
282
|
-
|
|
283
|
-
Source: packages/table-core/src/features/column-grouping/createGroupedRowModel.ts
|
|
284
|
-
|
|
285
|
-
### [MEDIUM] Confusing the `aggregationFn` signature with filter/sort signatures
|
|
286
|
-
|
|
287
|
-
Wrong:
|
|
288
|
-
|
|
289
|
-
```ts
|
|
290
|
-
// wrong arg names — first arg is columnId, not row
|
|
291
|
-
aggregationFn: (rowA, rowB, columnId) => /* ... */
|
|
292
|
-
|
|
293
|
-
// or: averaging via childRows includes already-aggregated sub-group sums
|
|
294
|
-
aggregationFn: (id, leaf, child) => child.reduce((a, r) => a + r.getValue(id), 0) / child.length
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
Correct:
|
|
298
|
-
|
|
299
|
-
```ts
|
|
300
|
-
// (columnId, leafRows, childRows)
|
|
301
|
-
// leafRows = all descendant non-grouped rows
|
|
302
|
-
// childRows = immediate children (may be sub-aggregates)
|
|
303
|
-
|
|
304
|
-
// For pure leaf averages, use leafRows:
|
|
305
|
-
const aggregationFn_mean: AggregationFn<any, any> = (columnId, leafRows) => {
|
|
306
|
-
let count = 0,
|
|
307
|
-
sum = 0
|
|
308
|
-
leafRows.forEach((row) => {
|
|
309
|
-
const value = row.getValue(columnId)
|
|
310
|
-
if (typeof value === 'number') {
|
|
311
|
-
count++
|
|
312
|
-
sum += value
|
|
313
|
-
}
|
|
314
|
-
})
|
|
315
|
-
return count ? sum / count : undefined
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// For nestable sums (reuse sub-aggregates), use childRows:
|
|
319
|
-
const aggregationFn_sum: AggregationFn<any, any> = (
|
|
320
|
-
columnId,
|
|
321
|
-
_leafRows,
|
|
322
|
-
childRows,
|
|
323
|
-
) => {
|
|
324
|
-
return childRows.reduce((acc, next) => {
|
|
325
|
-
const v = next.getValue(columnId)
|
|
326
|
-
return acc + (typeof v === 'number' ? v : 0)
|
|
327
|
-
}, 0)
|
|
328
|
-
}
|
|
329
|
-
```
|
|
58
|
+
Correct: `tableFeatures({ columnGroupingFeature, groupedRowModel: createGroupedRowModel() })`
|
|
330
59
|
|
|
331
|
-
|
|
60
|
+
The grouped slot and aggregation registry require `columnGroupingFeature`.
|
|
332
61
|
|
|
333
|
-
Source: packages/table-core/src/
|
|
62
|
+
Source: `packages/table-core/src/types/TableFeatures.ts#FeatureSlotPrereqs`
|
|
334
63
|
|
|
335
|
-
### [
|
|
64
|
+
### [HIGH] Treating rendered rows as underlying records
|
|
336
65
|
|
|
337
|
-
Wrong:
|
|
338
|
-
|
|
339
|
-
```ts
|
|
340
|
-
const table = useTable({
|
|
341
|
-
features,
|
|
342
|
-
columns,
|
|
343
|
-
data,
|
|
344
|
-
initialState: {
|
|
345
|
-
columnOrder: ['firstName', 'lastName', 'age', 'status'], // explicit
|
|
346
|
-
grouping: ['status'],
|
|
347
|
-
},
|
|
348
|
-
// status jumps to position 0 — columnOrder is "overridden"
|
|
349
|
-
})
|
|
350
|
-
```
|
|
66
|
+
Wrong: `const leafCount = table.getRowModel().flatRows.filter(row => !row.subRows.length).length`
|
|
351
67
|
|
|
352
68
|
Correct:
|
|
353
69
|
|
|
354
70
|
```ts
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
},
|
|
363
|
-
groupedColumnMode: false, // keep columnOrder intact
|
|
364
|
-
})
|
|
365
|
-
|
|
366
|
-
// Or hide grouped columns entirely:
|
|
367
|
-
// groupedColumnMode: 'remove'
|
|
71
|
+
const countLeafRows = (rows: typeof groupRow.subRows): number =>
|
|
72
|
+
rows.reduce(
|
|
73
|
+
(count, row) =>
|
|
74
|
+
count + (row.subRows.length ? countLeafRows(row.subRows) : 1),
|
|
75
|
+
0,
|
|
76
|
+
)
|
|
77
|
+
const leafCount = countLeafRows(groupRow.subRows)
|
|
368
78
|
```
|
|
369
79
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
### [LOW] Calling `getSelectedRowModel()` on a grouped table expecting grouped rows
|
|
80
|
+
Count descendants from one group row rather than the flattened render model,
|
|
81
|
+
where group rows and expanded rows may both appear. The current
|
|
82
|
+
`table.getRowModel().rows` is render order, while original dataset counts come
|
|
83
|
+
from the data owner.
|
|
375
84
|
|
|
376
|
-
|
|
85
|
+
Source: `docs/framework/react/guide/grouping.md`
|
|
377
86
|
|
|
378
|
-
|
|
379
|
-
// returns selection from the CORE model, not the grouped projection
|
|
380
|
-
const selectedRows = table.getSelectedRowModel().rows
|
|
381
|
-
// Doesn't reflect grouping — leaf rows only
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
Correct:
|
|
385
|
-
|
|
386
|
-
```ts
|
|
387
|
-
table.getSelectedRowModel() // selection from raw data
|
|
388
|
-
table.getFilteredSelectedRowModel() // selection within current filters
|
|
389
|
-
table.getGroupedSelectedRowModel() // selection within current groups
|
|
390
|
-
```
|
|
87
|
+
### [HIGH] Rendering every cell identically
|
|
391
88
|
|
|
392
|
-
|
|
89
|
+
Wrong: `render(cell.getValue())`
|
|
393
90
|
|
|
394
|
-
|
|
91
|
+
Correct: `render(cell.getIsPlaceholder() ? null : cell.getValue())`
|
|
395
92
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
Wrong:
|
|
399
|
-
|
|
400
|
-
```ts
|
|
401
|
-
// Hand-rolled groupBy + reduce, bypassing the table
|
|
402
|
-
const grouped = useMemo(() => {
|
|
403
|
-
const map = new Map<string, Person[]>()
|
|
404
|
-
data.forEach((row) => {
|
|
405
|
-
const key = row.status
|
|
406
|
-
if (!map.has(key)) map.set(key, [])
|
|
407
|
-
map.get(key)!.push(row)
|
|
408
|
-
})
|
|
409
|
-
return Array.from(map.entries()).map(([k, rows]) => ({
|
|
410
|
-
status: k,
|
|
411
|
-
avgAge: rows.reduce((s, r) => s + r.age, 0) / rows.length,
|
|
412
|
-
}))
|
|
413
|
-
}, [data])
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
Correct:
|
|
417
|
-
|
|
418
|
-
```ts
|
|
419
|
-
const features = tableFeatures({
|
|
420
|
-
columnGroupingFeature,
|
|
421
|
-
rowExpandingFeature,
|
|
422
|
-
groupedRowModel: createGroupedRowModel(),
|
|
423
|
-
expandedRowModel: createExpandedRowModel(),
|
|
424
|
-
aggregationFns,
|
|
425
|
-
})
|
|
426
|
-
const table = useTable({
|
|
427
|
-
features,
|
|
428
|
-
columns: columnHelper.columns([
|
|
429
|
-
columnHelper.accessor('status', { enableGrouping: true }),
|
|
430
|
-
columnHelper.accessor('age', { aggregationFn: 'mean' }),
|
|
431
|
-
]),
|
|
432
|
-
data,
|
|
433
|
-
})
|
|
434
|
-
table.setGrouping(['status'])
|
|
435
|
-
```
|
|
93
|
+
Placeholder and aggregated cells do not represent ordinary leaf values.
|
|
436
94
|
|
|
437
|
-
Source:
|
|
95
|
+
Source: `examples/react/grouping/src/main.tsx`
|
|
438
96
|
|
|
439
|
-
##
|
|
97
|
+
## API Discovery
|
|
440
98
|
|
|
441
|
-
|
|
442
|
-
- `tanstack-table/customizing-feature-behavior` — `aggregationFn` authoring
|
|
443
|
-
- `tanstack-table/row-selection` — `getGroupedSelectedRowModel` distinction
|
|
99
|
+
Inspect `node_modules/@tanstack/table-core/src/features/column-grouping/` and `src/fns/aggregationFns.ts`.
|