@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/sorting/SKILL.md
CHANGED
|
@@ -1,344 +1,80 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sorting
|
|
3
3
|
description: >
|
|
4
|
-
Sort
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
`getNextSortingOrder` / `clearSorting` / `getCanSort` / `getCanMultiSort`,
|
|
13
|
-
`manualSorting` for server-side, and fuzzy `compareItems` pairing.
|
|
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
|
+
Sort with rowSortingFeature, sortedRowModel, sortFns, multi-sort and removal options, sortUndefined, and manualSorting. Load for comparator direction, incoming server order, or product-specific sorting cycles.
|
|
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/sorting.md
|
|
22
|
-
- TanStack/table:packages/table-core/src/
|
|
23
|
-
- TanStack/table:
|
|
24
|
-
- TanStack/table:packages/table-core/src/features/row-sorting/rowSortingFeature.utils.ts
|
|
25
|
-
- TanStack/table:examples/react/sorting/src/main.tsx
|
|
13
|
+
- 'TanStack/table:docs/framework/react/guide/sorting.md'
|
|
14
|
+
- 'TanStack/table:packages/table-core/src/features/row-sorting'
|
|
15
|
+
- 'TanStack/table:examples/react/sorting'
|
|
26
16
|
---
|
|
27
17
|
|
|
28
|
-
This skill builds on `
|
|
18
|
+
This skill builds on `core`, `table-features`, and `client-vs-server`. Sorting state describes order; client processing requires a sorted model and server processing requires sorted input.
|
|
29
19
|
|
|
30
20
|
## Setup
|
|
31
21
|
|
|
32
22
|
```ts
|
|
33
23
|
import {
|
|
34
|
-
tableFeatures,
|
|
35
|
-
rowSortingFeature,
|
|
36
24
|
createSortedRowModel,
|
|
25
|
+
rowSortingFeature,
|
|
37
26
|
sortFns,
|
|
38
|
-
|
|
39
|
-
constructTable,
|
|
27
|
+
tableFeatures,
|
|
40
28
|
} from '@tanstack/table-core'
|
|
41
|
-
import type { SortingState } from '@tanstack/table-core'
|
|
42
|
-
|
|
43
|
-
type Person = {
|
|
44
|
-
firstName: string
|
|
45
|
-
lastName: string
|
|
46
|
-
age: number
|
|
47
|
-
status: 'single' | 'complicated' | 'relationship'
|
|
48
|
-
}
|
|
49
29
|
|
|
50
|
-
const features = tableFeatures({
|
|
30
|
+
export const features = tableFeatures({
|
|
51
31
|
rowSortingFeature,
|
|
52
32
|
sortedRowModel: createSortedRowModel(),
|
|
53
33
|
sortFns,
|
|
54
34
|
})
|
|
55
|
-
const columnHelper = createColumnHelper<typeof features, Person>()
|
|
56
|
-
|
|
57
|
-
const columns = columnHelper.columns([
|
|
58
|
-
columnHelper.accessor('firstName', { sortFn: 'alphanumeric' }),
|
|
59
|
-
columnHelper.accessor('lastName', {
|
|
60
|
-
sortUndefined: 'last',
|
|
61
|
-
sortDescFirst: false,
|
|
62
|
-
}),
|
|
63
|
-
columnHelper.accessor('age', { sortFn: 'basic' }),
|
|
64
|
-
])
|
|
65
|
-
|
|
66
|
-
const table = constructTable({
|
|
67
|
-
features,
|
|
68
|
-
columns,
|
|
69
|
-
data,
|
|
70
|
-
initialState: { sorting: [] satisfies SortingState },
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
table.setSorting([{ id: 'age', desc: true }])
|
|
74
35
|
```
|
|
75
36
|
|
|
76
37
|
## Core Patterns
|
|
77
38
|
|
|
78
|
-
### Clickable header sorting with multi-sort on Shift+click
|
|
79
|
-
|
|
80
|
-
```tsx
|
|
81
|
-
// From examples/react/sorting/src/main.tsx
|
|
82
|
-
{
|
|
83
|
-
headerGroup.headers.map((header) => (
|
|
84
|
-
<th
|
|
85
|
-
key={header.id}
|
|
86
|
-
onClick={header.column.getToggleSortingHandler()}
|
|
87
|
-
style={{ cursor: header.column.getCanSort() ? 'pointer' : 'default' }}
|
|
88
|
-
>
|
|
89
|
-
<table.FlexRender header={header} />
|
|
90
|
-
{{ asc: ' 🔼', desc: ' 🔽' }[header.column.getIsSorted() as string] ??
|
|
91
|
-
null}
|
|
92
|
-
</th>
|
|
93
|
-
))
|
|
94
|
-
}
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
`getToggleSortingHandler` already handles multi-sort when the user holds Shift (configurable via `isMultiSortEvent`).
|
|
98
|
-
|
|
99
|
-
### Custom `sortFn` for an enum
|
|
100
|
-
|
|
101
39
|
```ts
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
rowA,
|
|
105
|
-
rowB,
|
|
106
|
-
_columnId,
|
|
107
|
-
) => {
|
|
108
|
-
const statusOrder = ['single', 'complicated', 'relationship']
|
|
109
|
-
return (
|
|
110
|
-
statusOrder.indexOf(rowA.original.status) -
|
|
111
|
-
statusOrder.indexOf(rowB.original.status)
|
|
112
|
-
)
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
columnHelper.accessor('status', { sortFn: sortStatusFn })
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
Always return an ascending-order comparison. The row model multiplies by `-1` for descending and again for `invertSorting`.
|
|
119
|
-
|
|
120
|
-
### Direction control with `sortUndefined` and `invertSorting`
|
|
121
|
-
|
|
122
|
-
```ts
|
|
123
|
-
columnHelper.accessor('rank', {
|
|
124
|
-
invertSorting: true, // rank 1 above rank 2 even when "descending"
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
columnHelper.accessor('lastName', {
|
|
128
|
-
sortUndefined: 'last', // ABSOLUTE: end regardless of asc/desc
|
|
129
|
-
sortDescFirst: false,
|
|
130
|
-
})
|
|
40
|
+
const options = { enableSortingRemoval: false, enableMultiSort: true }
|
|
41
|
+
const numericColumn = { sortUndefined: 'last' as const }
|
|
131
42
|
```
|
|
132
43
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
### Server-side sorting
|
|
136
|
-
|
|
137
|
-
```tsx
|
|
138
|
-
const [sorting, setSorting] = useState<SortingState>([])
|
|
139
|
-
const { data } = useQuery({
|
|
140
|
-
queryKey: ['rows', sorting],
|
|
141
|
-
queryFn: () =>
|
|
142
|
-
fetch('/api/rows?sort=' + serialize(sorting)).then((r) => r.json()),
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
const table = useTable({
|
|
146
|
-
features: tableFeatures({ rowSortingFeature }),
|
|
147
|
-
// omit sortedRowModel from features — server sorts
|
|
148
|
-
columns,
|
|
149
|
-
data,
|
|
150
|
-
manualSorting: true,
|
|
151
|
-
state: { sorting },
|
|
152
|
-
onSortingChange: setSorting,
|
|
153
|
-
})
|
|
154
|
-
```
|
|
44
|
+
Configure sort cycles and undefined placement to match the product rather than relying on implicit defaults.
|
|
155
45
|
|
|
156
46
|
## Common Mistakes
|
|
157
47
|
|
|
158
|
-
### [
|
|
159
|
-
|
|
160
|
-
Wrong:
|
|
161
|
-
|
|
162
|
-
```tsx
|
|
163
|
-
{
|
|
164
|
-
accessorKey: 'fullName',
|
|
165
|
-
sortingFn: 'alphanumeric', // v8 name — falls through to sortFn_basic
|
|
166
|
-
}
|
|
167
|
-
// useTable({ sortingFns: { ...sortingFns, myFn } }) // v8 option name
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
Correct:
|
|
171
|
-
|
|
172
|
-
```tsx
|
|
173
|
-
import { sortFns, createSortedRowModel } from '@tanstack/react-table'
|
|
174
|
-
|
|
175
|
-
columnHelper.accessor('firstName', {
|
|
176
|
-
sortFn: 'alphanumeric',
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
const features = tableFeatures({
|
|
180
|
-
rowSortingFeature,
|
|
181
|
-
sortedRowModel: createSortedRowModel(),
|
|
182
|
-
sortFns: {
|
|
183
|
-
...sortFns,
|
|
184
|
-
myCustom: (a, b, id) => a.original[id] - b.original[id],
|
|
185
|
-
},
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
const table = useTable({ features, columns, data })
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
v9 renamed `columnDef.sortingFn → sortFn`, the fn registry slot `sortingFns → sortFns` (now registered on `features`), exported registry `sortingFns → sortFns`. The new column option defaults to `'auto'` and falls back to `sortFn_basic` when lookup misses — wrong names sort wrong, silently.
|
|
192
|
-
|
|
193
|
-
Source: packages/table-core/src/features/row-sorting/rowSortingFeature.utils.ts
|
|
194
|
-
|
|
195
|
-
### [MEDIUM] Expecting `sortUndefined: 'first' | 'last'` to work in v8
|
|
48
|
+
### [CRITICAL] Expecting manual mode to reorder
|
|
196
49
|
|
|
197
|
-
Wrong:
|
|
50
|
+
Wrong: `const options = { data: unsortedRows, manualSorting: true }`
|
|
198
51
|
|
|
199
|
-
|
|
200
|
-
// agent assumes numeric and literal forms are interchangeable
|
|
201
|
-
{ accessorKey: 'lastName', sortUndefined: -1 } // ascending-first, descending-LAST
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
Correct:
|
|
205
|
-
|
|
206
|
-
```tsx
|
|
207
|
-
// From examples/react/sorting/src/main.tsx
|
|
208
|
-
columnHelper.accessor((row) => row.lastName, {
|
|
209
|
-
id: 'lastName',
|
|
210
|
-
sortUndefined: 'last', // ABSOLUTE: always at end regardless of asc/desc
|
|
211
|
-
sortDescFirst: false,
|
|
212
|
-
})
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
v8 only had `false | -1 | 1`. v9 added `'first'` / `'last'`. Numeric flips with `desc`; literals are absolute.
|
|
216
|
-
|
|
217
|
-
Source: packages/table-core/src/features/row-sorting/createSortedRowModel.ts
|
|
218
|
-
|
|
219
|
-
### [MEDIUM] Custom `sortFn` factors `desc` in itself
|
|
220
|
-
|
|
221
|
-
Wrong:
|
|
222
|
-
|
|
223
|
-
```tsx
|
|
224
|
-
// takes sort direction into account, breaks the toggle
|
|
225
|
-
const customSort: SortFn<any, any> = (a, b, id, desc) => {
|
|
226
|
-
// desc isn't even a parameter — agents try to detect via state
|
|
227
|
-
const cmp = a.original[id] - b.original[id]
|
|
228
|
-
return desc ? -cmp : cmp
|
|
229
|
-
}
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
Correct:
|
|
233
|
-
|
|
234
|
-
```tsx
|
|
235
|
-
// From examples/react/sorting/src/main.tsx
|
|
236
|
-
// Always return ascending; the row model handles desc & invertSorting.
|
|
237
|
-
const sortStatusFn: SortFn<any, any> = (rowA, rowB, _columnId) => {
|
|
238
|
-
const statusOrder = ['single', 'complicated', 'relationship']
|
|
239
|
-
return (
|
|
240
|
-
statusOrder.indexOf(rowA.original.status) -
|
|
241
|
-
statusOrder.indexOf(rowB.original.status)
|
|
242
|
-
)
|
|
243
|
-
}
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
From the docs guide: "The comparison function does not need to take whether or not the column is in descending or ascending order into account. The row models will take care of that logic." Doubly-flipping yields broken toggles.
|
|
247
|
-
|
|
248
|
-
Source: packages/table-core/src/features/row-sorting/createSortedRowModel.ts
|
|
249
|
-
|
|
250
|
-
### [MEDIUM] Fuzzy filter without a fuzzy-aware `sortFn`
|
|
251
|
-
|
|
252
|
-
Wrong:
|
|
253
|
-
|
|
254
|
-
```ts
|
|
255
|
-
columnHelper.accessor('fullName', {
|
|
256
|
-
filterFn: 'fuzzy',
|
|
257
|
-
// BUG: rows sort alphabetically, not by match rank
|
|
258
|
-
})
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
Correct:
|
|
52
|
+
Correct: `const options = { data: serverSortedRows, manualSorting: true }`
|
|
262
53
|
|
|
263
|
-
|
|
264
|
-
import { compareItems } from '@tanstack/match-sorter-utils'
|
|
265
|
-
|
|
266
|
-
const fuzzySort: SortFn<typeof features, Person> = (rowA, rowB, columnId) => {
|
|
267
|
-
let dir = 0
|
|
268
|
-
if (rowA.columnFiltersMeta[columnId]) {
|
|
269
|
-
dir = compareItems(
|
|
270
|
-
rowA.columnFiltersMeta[columnId].itemRank!,
|
|
271
|
-
rowB.columnFiltersMeta[columnId].itemRank!,
|
|
272
|
-
)
|
|
273
|
-
}
|
|
274
|
-
return dir === 0 ? sortFns.alphanumeric(rowA, rowB, columnId) : dir
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
columnHelper.accessor('fullName', { filterFn: 'fuzzy', sortFn: fuzzySort })
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
The fuzzy filter writes `{ itemRank }` into `row.columnFiltersMeta[columnId]` via `addMeta`. Without a sortFn that reads it, results sort alphabetically and defeat the fuzzy ranking.
|
|
54
|
+
Manual sorting bypasses `sortedRowModel` and trusts incoming order.
|
|
281
55
|
|
|
282
|
-
Source:
|
|
56
|
+
Source: `packages/table-core/src/features/row-sorting/rowSortingFeature.types.ts`
|
|
283
57
|
|
|
284
|
-
### [
|
|
58
|
+
### [HIGH] Reversing inside the comparator
|
|
285
59
|
|
|
286
|
-
Wrong:
|
|
60
|
+
Wrong: `const newest: SortFn<any, any> = (a, b, id) => b.getValue<number>(id) - a.getValue<number>(id)`
|
|
287
61
|
|
|
288
|
-
|
|
289
|
-
// getCanSort() returns false even though manualSorting is true
|
|
290
|
-
const table = useTable({
|
|
291
|
-
manualSorting: true,
|
|
292
|
-
columns: [
|
|
293
|
-
{ id: 'computed', header: 'Computed', cell: (info) => row.x + row.y },
|
|
294
|
-
],
|
|
295
|
-
})
|
|
296
|
-
```
|
|
62
|
+
Correct: `const numeric: SortFn<any, any> = (a, b, id) => a.getValue<number>(id) - b.getValue<number>(id)`
|
|
297
63
|
|
|
298
|
-
|
|
64
|
+
Return ascending comparison only; Table reverses it when sorting is descending.
|
|
299
65
|
|
|
300
|
-
|
|
301
|
-
columnHelper.display({
|
|
302
|
-
id: 'computed',
|
|
303
|
-
header: 'Computed',
|
|
304
|
-
enableSorting: true, // force-enable for manualSorting
|
|
305
|
-
cell: (info) => info.row.original.x + info.row.original.y,
|
|
306
|
-
})
|
|
307
|
-
```
|
|
66
|
+
Source: `docs/framework/react/guide/sorting.md#custom-sorting-functions`
|
|
308
67
|
|
|
309
|
-
|
|
68
|
+
### [MEDIUM] Leaving ambiguous sort policy
|
|
310
69
|
|
|
311
|
-
|
|
70
|
+
Wrong: `const options = { enableSortingRemoval: true }`
|
|
312
71
|
|
|
313
|
-
|
|
72
|
+
Correct: `const options = { enableSortingRemoval: false }; const rankColumn = { sortUndefined: 'last' as const }`
|
|
314
73
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
```ts
|
|
318
|
-
const [sorting, setSorting] = useState([])
|
|
319
|
-
const sortedData = useMemo(
|
|
320
|
-
() => [...data].sort(/* …custom… */),
|
|
321
|
-
[data, sorting],
|
|
322
|
-
)
|
|
323
|
-
// then uses sortedData directly, bypassing the table
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
Correct:
|
|
327
|
-
|
|
328
|
-
```ts
|
|
329
|
-
const features = tableFeatures({
|
|
330
|
-
rowSortingFeature,
|
|
331
|
-
sortedRowModel: createSortedRowModel(),
|
|
332
|
-
sortFns,
|
|
333
|
-
})
|
|
334
|
-
const table = useTable({ features, columns, data })
|
|
335
|
-
// table.setSorting(...), column.toggleSorting(), header.getToggleSortingHandler()
|
|
336
|
-
```
|
|
74
|
+
Undefined placement and removal cycles can differ from expected product behavior unless configured.
|
|
337
75
|
|
|
338
|
-
Source:
|
|
76
|
+
Source: `packages/table-core/src/features/row-sorting/rowSortingFeature.types.ts`
|
|
339
77
|
|
|
340
|
-
##
|
|
78
|
+
## API Discovery
|
|
341
79
|
|
|
342
|
-
|
|
343
|
-
- `tanstack-table/filtering` — fuzzy filter pattern that pairs with `fuzzySort`
|
|
344
|
-
- `tanstack-table/state-management` — `manualSorting` + server-side state ownership
|
|
80
|
+
Inspect `node_modules/@tanstack/table-core/src/features/row-sorting/` and `src/fns/sortFns.ts` for current names and comparator contracts.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: table-features
|
|
3
|
+
description: >
|
|
4
|
+
Register TanStack Table v9 tableFeatures, feature plugins, create*RowModel factories, and function registries in prerequisite order. Load when an option, state slice, or instance API is missing, or when choosing explicit features versus stockFeatures.
|
|
5
|
+
metadata:
|
|
6
|
+
type: sub-skill
|
|
7
|
+
library: '@tanstack/table-core'
|
|
8
|
+
library_version: '9.0.0-beta.42'
|
|
9
|
+
requires: ['core']
|
|
10
|
+
sources:
|
|
11
|
+
- 'TanStack/table:docs/guide/row-models.md'
|
|
12
|
+
- 'TanStack/table:packages/table-core/src/types/TableFeatures.ts'
|
|
13
|
+
- 'TanStack/table:packages/table-core/src/features/stockFeatures.ts'
|
|
14
|
+
- 'TanStack/table:packages/table-core/src/core/table/constructTable.ts'
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
This skill builds on `core`. Read it first for the headless model and stable inputs.
|
|
18
|
+
|
|
19
|
+
## Setup
|
|
20
|
+
|
|
21
|
+
<!-- skill-snippet:check -->
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import {
|
|
25
|
+
aggregationFns,
|
|
26
|
+
columnGroupingFeature,
|
|
27
|
+
createFilteredRowModel,
|
|
28
|
+
createSortedRowModel,
|
|
29
|
+
columnFilteringFeature,
|
|
30
|
+
filterFns,
|
|
31
|
+
rowSortingFeature,
|
|
32
|
+
sortFns,
|
|
33
|
+
tableFeatures,
|
|
34
|
+
} from '@tanstack/table-core'
|
|
35
|
+
|
|
36
|
+
export const features = tableFeatures({
|
|
37
|
+
columnFilteringFeature,
|
|
38
|
+
filteredRowModel: createFilteredRowModel(),
|
|
39
|
+
filterFns,
|
|
40
|
+
columnGroupingFeature,
|
|
41
|
+
aggregationFns,
|
|
42
|
+
rowSortingFeature,
|
|
43
|
+
sortedRowModel: createSortedRowModel(),
|
|
44
|
+
sortFns,
|
|
45
|
+
})
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Core Patterns
|
|
49
|
+
|
|
50
|
+
### Register feature before its dependent slot
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
const features = tableFeatures({
|
|
54
|
+
rowSortingFeature,
|
|
55
|
+
sortedRowModel: createSortedRowModel(),
|
|
56
|
+
})
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`tableFeatures` checks slot prerequisites and its inferred type gates APIs throughout the table.
|
|
60
|
+
|
|
61
|
+
### Register named function slots with their features
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
const features = tableFeatures({
|
|
65
|
+
columnFilteringFeature,
|
|
66
|
+
filterFns,
|
|
67
|
+
rowSortingFeature,
|
|
68
|
+
sortFns,
|
|
69
|
+
columnGroupingFeature,
|
|
70
|
+
aggregationFns,
|
|
71
|
+
})
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`filterFns`, `sortFns`, and `aggregationFns` are feature slots, not table
|
|
75
|
+
options. They respectively require `columnFilteringFeature`,
|
|
76
|
+
`rowSortingFeature`, and `columnGroupingFeature`. A registered key can be used
|
|
77
|
+
as a typed string name; pass a function directly when no registry name is
|
|
78
|
+
needed.
|
|
79
|
+
|
|
80
|
+
### Prefer explicit features
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
const features = tableFeatures({ columnFilteringFeature })
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Use `stockFeatures` only for deliberate kitchen-sink or temporary migration behavior.
|
|
87
|
+
|
|
88
|
+
## Common Mistakes
|
|
89
|
+
|
|
90
|
+
### [CRITICAL] Calling an unregistered feature API
|
|
91
|
+
|
|
92
|
+
Wrong:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
const features = tableFeatures({})
|
|
96
|
+
table.setSorting([{ id: 'name', desc: false }])
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Correct:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
const features = tableFeatures({ rowSortingFeature })
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Optional feature state and APIs are installed only when their feature is registered.
|
|
106
|
+
|
|
107
|
+
Source: `packages/table-core/src/core/table/constructTable.ts`
|
|
108
|
+
|
|
109
|
+
### [HIGH] Omitting a slot prerequisite
|
|
110
|
+
|
|
111
|
+
Wrong:
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
const features = tableFeatures({ sortedRowModel: createSortedRowModel() })
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Correct:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
const features = tableFeatures({
|
|
121
|
+
rowSortingFeature,
|
|
122
|
+
sortedRowModel: createSortedRowModel(),
|
|
123
|
+
})
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The sorted model slot requires `rowSortingFeature`; the same rule applies to every mapped slot.
|
|
127
|
+
|
|
128
|
+
Source: `packages/table-core/src/types/TableFeatures.ts#FeatureSlotPrereqs`
|
|
129
|
+
|
|
130
|
+
### [MEDIUM] Shipping all features by default
|
|
131
|
+
|
|
132
|
+
Wrong:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
const features = stockFeatures
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Correct:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
const features = tableFeatures({
|
|
142
|
+
rowSortingFeature,
|
|
143
|
+
sortedRowModel: createSortedRowModel(),
|
|
144
|
+
})
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`stockFeatures` registers every stock plugin and processing slot, defeating v9's normal tree-shaking strategy.
|
|
148
|
+
|
|
149
|
+
Source: `packages/table-core/src/features/stockFeatures.ts`
|
|
150
|
+
|
|
151
|
+
## API Discovery
|
|
152
|
+
|
|
153
|
+
Inspect `node_modules/@tanstack/table-core/src/types/TableFeatures.ts` for current slots and `FeatureSlotPrereqs`, and `src/features/stockFeatures.ts` for the stock inventory.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: typescript
|
|
3
|
+
description: >
|
|
4
|
+
Preserve TanStack Table v9 inference with createColumnHelper, columns(), tableOptions, tableFeatures, and metaHelper. Load for ColumnDef errors, reusable tables, typed meta, named registries, or unnecessary manual feature generics.
|
|
5
|
+
metadata:
|
|
6
|
+
type: sub-skill
|
|
7
|
+
library: '@tanstack/table-core'
|
|
8
|
+
library_version: '9.0.0-beta.42'
|
|
9
|
+
requires: ['core', 'table-features']
|
|
10
|
+
sources:
|
|
11
|
+
- 'TanStack/table:docs/guide/helpers.md'
|
|
12
|
+
- 'TanStack/table:docs/guide/column-defs.md'
|
|
13
|
+
- 'TanStack/table:docs/guide/table-and-column-meta.md'
|
|
14
|
+
- 'TanStack/table:packages/table-core/src/helpers'
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
This skill builds on `core` and `table-features`. Let the feature object and helpers carry types through userland.
|
|
18
|
+
|
|
19
|
+
## Setup
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import {
|
|
23
|
+
createColumnHelper,
|
|
24
|
+
metaHelper,
|
|
25
|
+
tableFeatures,
|
|
26
|
+
} from '@tanstack/table-core'
|
|
27
|
+
|
|
28
|
+
type Person = { id: string; age: number }
|
|
29
|
+
type ColumnMeta = { align?: 'start' | 'end' }
|
|
30
|
+
const features = tableFeatures({ columnMeta: metaHelper<ColumnMeta>() })
|
|
31
|
+
const helper = createColumnHelper<typeof features, Person>()
|
|
32
|
+
export const columns = helper.columns([
|
|
33
|
+
helper.accessor('age', { meta: { align: 'end' } }),
|
|
34
|
+
])
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Core Patterns
|
|
38
|
+
|
|
39
|
+
### Preserve heterogeneous accessor values
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
const columns = helper.columns([
|
|
43
|
+
helper.accessor('id', { header: 'ID' }),
|
|
44
|
+
helper.accessor('age', { header: 'Age' }),
|
|
45
|
+
])
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`columns()` preserves each accessor's `TValue` instead of widening the array.
|
|
49
|
+
|
|
50
|
+
### Compose options through the helper
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
const defaults = tableOptions<typeof features, Person>({
|
|
54
|
+
defaultColumn: { meta: { align: 'start' } },
|
|
55
|
+
})
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Use `tableOptions` for reusable fragments; direct adapter options are enough for one-offs.
|
|
59
|
+
|
|
60
|
+
## Common Mistakes
|
|
61
|
+
|
|
62
|
+
### [HIGH] Erasing accessor value inference
|
|
63
|
+
|
|
64
|
+
Wrong:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
const columns: ColumnDef<typeof features, Person, unknown>[] = [
|
|
68
|
+
helper.accessor('age', {}),
|
|
69
|
+
]
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Correct:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
const columns = helper.columns([helper.accessor('age', {})])
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The broad annotation discards the accessor-specific `number` value type.
|
|
79
|
+
|
|
80
|
+
Source: `docs/guide/helpers.md#createcolumnhelper`
|
|
81
|
+
|
|
82
|
+
### [MEDIUM] Threading internal feature generics manually
|
|
83
|
+
|
|
84
|
+
Wrong:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
type Features = TableFeatures
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Correct:
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
type Features = typeof features
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The concrete registry is the source of feature-gated APIs and registry keys.
|
|
97
|
+
|
|
98
|
+
Source: `packages/table-core/src/types/TableFeatures.ts`
|
|
99
|
+
|
|
100
|
+
### [MEDIUM] Globally merging per-table meta
|
|
101
|
+
|
|
102
|
+
Wrong:
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
declare module '@tanstack/table-core' {
|
|
106
|
+
interface ColumnMeta<TData, TValue> {
|
|
107
|
+
align?: string
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Correct:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
const features = tableFeatures({
|
|
116
|
+
columnMeta: metaHelper<{ align?: 'start' | 'end' }>(),
|
|
117
|
+
})
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
V9 type-only feature slots keep meta types scoped to the table factory.
|
|
121
|
+
|
|
122
|
+
Source: `docs/guide/table-and-column-meta.md`
|
|
123
|
+
|
|
124
|
+
## API Discovery
|
|
125
|
+
|
|
126
|
+
Inspect `node_modules/@tanstack/table-core/src/helpers/` and the signatures re-exported by `src/index.ts`; avoid copying deep internal generic signatures into application code.
|
|
@@ -21,7 +21,7 @@ export function buildHeaderGroups<
|
|
|
21
21
|
allColumns: Array<Column<TFeatures, TData, TValue>>,
|
|
22
22
|
columnsToGroup: Array<Column<TFeatures, TData, TValue>>,
|
|
23
23
|
table: Table_Internal<TFeatures, TData>,
|
|
24
|
-
headerFamily?: 'center' | '
|
|
24
|
+
headerFamily?: 'center' | 'start' | 'end',
|
|
25
25
|
) {
|
|
26
26
|
// Find the max depth of the columns:
|
|
27
27
|
// build the leaf column row
|