@jielga/tmdatagrid 1.0.0 → 1.0.2

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.
Files changed (78) hide show
  1. package/README.md +8 -8
  2. package/dist/index.d.ts +225 -225
  3. package/dist/index.js +58 -50
  4. package/dist/index.js.map +1 -1
  5. package/dist/styles.css +1 -1
  6. package/package.json +3 -2
  7. package/skills/appearance/SKILL.md +322 -0
  8. package/skills/cell-selection/SKILL.md +240 -0
  9. package/skills/columns/SKILL.md +261 -86
  10. package/skills/data/SKILL.md +289 -0
  11. package/skills/editing/SKILL.md +492 -0
  12. package/skills/editing/references/editing-api.md +124 -0
  13. package/skills/editing/references/editors-and-validation.md +198 -0
  14. package/skills/filtering/SKILL.md +344 -0
  15. package/skills/getting-started/SKILL.md +48 -27
  16. package/skills/grouping/SKILL.md +264 -0
  17. package/skills/options/SKILL.md +31 -20
  18. package/skills/rows/SKILL.md +369 -0
  19. package/skills/rows/references/rows-api.md +117 -0
  20. package/skills/server-side/SKILL.md +7 -7
  21. package/skills/testing/SKILL.md +12 -12
  22. package/src/tmdatagrid/TMDataGridContext.ts +2 -2
  23. package/src/tmdatagrid/components/TMDataGrid.module.css +2 -2
  24. package/src/tmdatagrid/components/TMDataGrid.tsx +5 -5
  25. package/src/tmdatagrid/components/TMDataGridCellEditor.tsx +4 -4
  26. package/src/tmdatagrid/components/TMDataGridColumnsPanel.tsx +2 -2
  27. package/src/tmdatagrid/components/TMDataGridDetailsColumn.tsx +6 -6
  28. package/src/tmdatagrid/components/TMDataGridEditActions.tsx +2 -2
  29. package/src/tmdatagrid/components/TMDataGridEditColumn.tsx +4 -4
  30. package/src/tmdatagrid/components/TMDataGridEntryRows.tsx +6 -6
  31. package/src/tmdatagrid/components/TMDataGridFilterPanel.tsx +6 -6
  32. package/src/tmdatagrid/components/TMDataGridFilterPills.module.css +2 -2
  33. package/src/tmdatagrid/components/TMDataGridFilterPills.tsx +1 -1
  34. package/src/tmdatagrid/components/TMDataGridFooter.module.css +1 -1
  35. package/src/tmdatagrid/components/TMDataGridFooter.tsx +12 -6
  36. package/src/tmdatagrid/components/TMDataGridGroupColumn.module.css +1 -1
  37. package/src/tmdatagrid/components/TMDataGridGroupColumn.tsx +5 -5
  38. package/src/tmdatagrid/components/TMDataGridHeaderCell.module.css +8 -8
  39. package/src/tmdatagrid/components/TMDataGridHeaderCell.tsx +12 -12
  40. package/src/tmdatagrid/components/TMDataGridRowNumberColumn.tsx +4 -4
  41. package/src/tmdatagrid/components/TMDataGridSearch.tsx +5 -5
  42. package/src/tmdatagrid/components/TMDataGridSelectColumn.tsx +8 -8
  43. package/src/tmdatagrid/components/TMDataGridTable.module.css +18 -18
  44. package/src/tmdatagrid/components/TMDataGridTable.tsx +116 -116
  45. package/src/tmdatagrid/components/TMDataGridToolbar.tsx +5 -5
  46. package/src/tmdatagrid/components/editors/TMDataGridBooleanEditor.tsx +1 -1
  47. package/src/tmdatagrid/components/editors/TMDataGridDateEditor.tsx +2 -2
  48. package/src/tmdatagrid/components/editors/TMDataGridMultiSelectEditor.tsx +1 -1
  49. package/src/tmdatagrid/components/editors/TMDataGridNumberEditor.tsx +1 -1
  50. package/src/tmdatagrid/components/editors/TMDataGridSelectEditor.tsx +2 -2
  51. package/src/tmdatagrid/components/editors/editorShared.ts +3 -3
  52. package/src/tmdatagrid/components/filters/DgDateRangeFilter.tsx +1 -1
  53. package/src/tmdatagrid/components/filters/DgRangeSliderFilter.tsx +1 -1
  54. package/src/tmdatagrid/components/filters/DgTriStateFilter.tsx +1 -1
  55. package/src/tmdatagrid/components/filters/TMDataGridFilterValueInput.tsx +2 -2
  56. package/src/tmdatagrid/components/sticky.module.css +8 -8
  57. package/src/tmdatagrid/core/autosize.ts +4 -4
  58. package/src/tmdatagrid/core/capabilities.ts +17 -17
  59. package/src/tmdatagrid/core/cellExport.ts +13 -13
  60. package/src/tmdatagrid/core/cellNavigation.ts +6 -6
  61. package/src/tmdatagrid/core/cellRange.ts +4 -4
  62. package/src/tmdatagrid/core/columnOptions.ts +2 -2
  63. package/src/tmdatagrid/core/columnOrdering.ts +2 -2
  64. package/src/tmdatagrid/core/columnUtils.ts +3 -3
  65. package/src/tmdatagrid/core/editEngine.ts +49 -49
  66. package/src/tmdatagrid/core/expanding.ts +5 -5
  67. package/src/tmdatagrid/core/filterControls.ts +5 -5
  68. package/src/tmdatagrid/core/filterOperators.ts +14 -14
  69. package/src/tmdatagrid/core/labels.ts +8 -8
  70. package/src/tmdatagrid/core/matchHighlight.ts +4 -4
  71. package/src/tmdatagrid/core/persistence.ts +8 -8
  72. package/src/tmdatagrid/core/quickSearch.ts +8 -8
  73. package/src/tmdatagrid/core/rowPinning.ts +3 -3
  74. package/src/tmdatagrid/core/rowSelection.ts +12 -12
  75. package/src/tmdatagrid/core/sizes.ts +1 -1
  76. package/src/tmdatagrid/core/summary.ts +3 -3
  77. package/src/tmdatagrid/useTMDataGrid.tsx +79 -79
  78. package/skills/features/SKILL.md +0 -352
@@ -1,27 +1,35 @@
1
1
  ---
2
2
  name: columns
3
3
  description: >
4
- Define TMDataGrid columns with createTMDataGridColumnHelper: column meta
5
- (label, type, flex, align, enableOrdering), fluid minmax sizing versus fixed
6
- width, minSize and maxSize, per-column
7
- enableSorting/enableColumnFilter/enableHiding/enablePinning/ enableResizing,
8
- the generated SELECT_COLUMN_ID checkbox column, and the shared filter function
9
- with its operator list and isFilterActive. Load when adding or changing
10
- columns, controlling widths, or wiring column filters.
4
+ Define and arrange TMDataGrid columns. Covers createTMDataGridColumnHelper,
5
+ every column meta field (label, type, options, flex, align, autoSize,
6
+ enableOrdering, defaultFilterOperator, filterControl, editable, editField,
7
+ editor, validate), the six column types, fluid minmax sizing versus fixed
8
+ width with minSize / maxSize / size, autosizing and autosizeColumn, hiding
9
+ through enableHiding and the columns panel, pinning and why a pinned column
10
+ becomes fixed-width, ordering with enableColumnOrdering, meta.enableOrdering,
11
+ moveColumn, moveColumnByStep, getStepTargetColumn and the pinned regions,
12
+ resetSettings, sorting with multi-sort through isMultiSortEvent and a custom
13
+ sortFn, and the generated lanes. Load when adding or changing columns,
14
+ controlling widths, hiding, pinning, reordering or sorting them.
11
15
  metadata:
12
16
  type: core
13
17
  library: '@jielga/tmdatagrid'
14
- library_version: '1.0.0'
18
+ library_version: '1.0.2'
15
19
  sources:
16
20
  - 'Jielga/TMDataGrid:src/docs/columns.md'
17
- - 'Jielga/TMDataGrid:src/tmdatagrid/core/filterOperators.ts'
21
+ - 'Jielga/TMDataGrid:src/docs/column-layout.md'
22
+ - 'Jielga/TMDataGrid:src/docs/sorting.md'
18
23
  - 'Jielga/TMDataGrid:src/tmdatagrid/core/columnUtils.ts'
24
+ - 'Jielga/TMDataGrid:src/tmdatagrid/core/columnOrdering.ts'
25
+ - 'Jielga/TMDataGrid:src/tmdatagrid/core/autosize.ts'
19
26
  ---
20
27
 
21
- # TMDataGrid — Columns
28
+ # TMDataGrid - Columns
22
29
 
23
30
  `createTMDataGridColumnHelper<TData>()` returns a TanStack column helper bound to
24
- the grid feature set, which gives `meta` and `filterFn` their correct types.
31
+ the grid's feature set, which is what gives `meta` and `filterFn` their correct
32
+ types.
25
33
 
26
34
  ```tsx
27
35
  import { createTMDataGridColumnHelper } from "@jielga/tmdatagrid";
@@ -51,13 +59,41 @@ column model.
51
59
  | Field | Type | Default | Description |
52
60
  | --- | --- | --- | --- |
53
61
  | `label` | `string` | String header, or column id | Name used in menus and the column manager. Required when `header` is a component. |
54
- | `type` | `"string" \| "number"` | `"string"` | Determines which filter operators are offered. |
62
+ | `type` | `TMDataGridColumnType` | `"string"` | Picks the filter operators, and the cell editor once editing is on. |
63
+ | `options` | `TMDataGridOptionsSource` | – | Choices for a `select` / `multiSelect` column: an array, `"faceted"`, or a function. One declaration feeds the filter panel and the editor. |
55
64
  | `flex` | `number` | `1` | Share of the remaining width. |
56
65
  | `align` | `"left" \| "right" \| "center"` | `"left"` | Applied to both header and cells. |
66
+ | `autoSize` | `boolean` | `false` | Size to the widest mounted content once, after the first rows render. |
57
67
  | `enableOrdering` | `boolean` | `true` | `false` keeps the column where it is. |
68
+ | `defaultFilterOperator` | `TMDataGridFilterOperator` | The type's default | The operator a fresh filter on this column starts with. |
69
+ | `filterControl` | `TMDataGridFilterControlComponent` | By `meta.type` | Replaces the value control in this column's filter row. Module scope. |
70
+ | `editable` | `boolean \| ((row) => boolean)` | editable where a field maps | Whether this column's cells edit. |
71
+ | `editField` | `string` | The `accessorKey` | The data path an edit writes to. The only way an `accessorFn` column edits. |
72
+ | `editor` | `TMDataGridEditorComponent` | By `meta.type` | Replaces the cell editor. Module scope. |
73
+ | `validate` | `TMDataGridFieldValidate` | – | Field-level validation. A bare schema means `onChange`. |
58
74
 
59
75
  `enableOrdering` lives in `meta` because column ordering is the one feature
60
- TanStack defines no column option for. See the `features` skill.
76
+ TanStack defines no column option for. The four editing fields only act once
77
+ `editMode` is set: see the `editing` skill. `filterControl` and
78
+ `defaultFilterOperator` belong to the `filtering` skill.
79
+
80
+ ### Column types
81
+
82
+ `meta.type` is one of `"string"`, `"number"`, `"boolean"`, `"date"`,
83
+ `"select"`, `"multiSelect"`. It decides three things at once: the operators the
84
+ filter panel offers, the control that filter row renders, and the editor a cell
85
+ opens. `select` and `multiSelect` read their choices from `meta.options`.
86
+
87
+ ```tsx
88
+ columnHelper.accessor("hired", { header: "Hired", meta: { type: "date" } });
89
+ columnHelper.accessor("department", {
90
+ header: "Department",
91
+ meta: { type: "select", options: ["Engineering", "Sales", "Support"] },
92
+ });
93
+ ```
94
+
95
+ Dates travel as ISO `YYYY-MM-DD` strings and booleans as `"true"` / `"false"`,
96
+ so the filter model stays plain JSON whatever the type.
61
97
 
62
98
  ## Sizing
63
99
 
@@ -66,15 +102,10 @@ Columns are fluid. Each track is `minmax(minSize, flex fr)`.
66
102
  | Option | Effect |
67
103
  | --- | --- |
68
104
  | `minSize` | Minimum width, and the column's contribution to the grid minimum width. Defaults to `80`. |
69
- | `meta.flex` | Share of the remaining width. |
105
+ | `meta.flex` | Share of the remaining width. Defaults to `1`. |
70
106
  | `minSize === maxSize` | Fixed width. The column is never fluid. |
71
107
  | `size` | Applied once the column becomes fixed by resizing or pinning. |
72
108
 
73
- A column switches to a fixed pixel width when resized or pinned. Pinning requires
74
- it because sticky offsets are calculated from `getSize()`, which cannot resolve
75
- an `fr` value. The grid stores the column's rendered width in `columnSizing` at
76
- the moment it is pinned, so its width does not change.
77
-
78
109
  ```tsx
79
110
  // Fixed 64px action column that never flexes.
80
111
  columnHelper.display({
@@ -85,112 +116,256 @@ columnHelper.display({
85
116
  });
86
117
  ```
87
118
 
119
+ Double-clicking a resize divider autosizes the column to its widest **mounted**
120
+ content - under virtualization the unmounted rows do not exist to be measured,
121
+ so the width fits the visible window plus overscan. The result is clamped to
122
+ `minSize`/`maxSize` and written into `columnSizing`, so it persists and a later
123
+ drag takes over. `meta.autoSize: true` runs it once after the first rows render,
124
+ unless a persisted or user-set width already covers the column, and
125
+ `autosizeColumn({ table, columnId, container })` is exported for menus and
126
+ consumer code.
127
+
128
+ ## Hiding, pinning and ordering
129
+
130
+ All three write state that persists together, so a grid comes back arranged the
131
+ way it was left. `resetSettings()` from the hook clears visibility, order,
132
+ pinning and widths in one go, and the columns panel offers it as **Reset
133
+ layout**.
134
+
135
+ **Hiding** is `columnVisibility`, driven by "Hide column" in a column menu and by
136
+ `TMDataGrid.ColumnsButton` with the panel behind it.
137
+
138
+ **Pinning** is "Pin to left" / "Pin to right" in the column menu. A pinned
139
+ column also becomes fixed-width: sticky offsets are computed from `getSize()`,
140
+ which cannot resolve an `fr` value, so the grid stores the rendered width in
141
+ `columnSizing` at the moment it is pinned and nothing jumps.
142
+
143
+ **Ordering** is header dragging plus "Move left" / "Move right". A column can
144
+ only move **within its own pinned region** - pinning splits the grid into left,
145
+ centre and right, then `columnOrder` sequences the centre while
146
+ `columnPinning.left` and `.right` sequence the pinned lanes. Unpin a column
147
+ first to move it out of one. A neighbour that cannot move acts as a wall rather
148
+ than being stepped over, and columns inside a header group are not movable in
149
+ either direction, because `columnOrder` sequences leaf columns.
150
+
151
+ ```tsx
152
+ import { moveColumn, moveColumnByStep } from "@jielga/tmdatagrid";
153
+
154
+ moveColumn({ table, columnId: "salary", targetId: "age", side: "before" });
155
+ moveColumnByStep({ table, columnId: "salary", direction: 1 });
156
+ ```
157
+
158
+ Both are no-ops for a move that is not allowed, including one across regions.
159
+ `getStepTargetColumn({ table, columnId, direction })` returns the column a step
160
+ would swap with, or `null` at a region edge - what the menu items use to disable
161
+ themselves.
162
+
163
+ `columnOrder` is stored as the **complete** leaf order, hidden and pinned
164
+ columns included, so a column keeps its position when it is later shown or
165
+ unpinned. A column added to the definitions later is not in the stored order and
166
+ is appended at the end until it is moved.
167
+
168
+ ## Sorting
169
+
170
+ On by default: click a header to sort, again to reverse, a third time to clear.
171
+ Shift+click a second header **adds** it to the sort, and each sorted header then
172
+ shows its priority beside the arrow. A plain click still replaces the whole
173
+ sort.
174
+
175
+ This is TanStack's own `isMultiSortEvent`, so `enableMultiSort`,
176
+ `maxMultiSortColCount` and a custom `isMultiSortEvent` pass straight through:
177
+
178
+ ```tsx
179
+ const grid = useTMDataGrid({
180
+ data,
181
+ columns,
182
+ maxMultiSortColCount: 3,
183
+ isMultiSortEvent: (event) => event.ctrlKey,
184
+ initialState: { sorting: [{ id: "lastName", desc: false }] },
185
+ });
186
+ ```
187
+
188
+ `sortFn` on a column takes any registered name or a
189
+ `(rowA, rowB, columnId) => number` function - v9's name for what v8 called
190
+ `sortingFn`, and a rename an agent will reproduce wrongly from memory. Sorting writes
191
+ TanStack's `sorting` state, an array of `{ id, desc }` in priority order. It is
192
+ a **data** slice, persisted under `dataKey`, while the column layout below is a
193
+ settings slice under `settingsKey`.
194
+
88
195
  ## Column-level feature options
89
196
 
90
197
  Standard TanStack column options. Each also removes the corresponding interface.
91
198
 
92
199
  | Option | Effect when `false` |
93
200
  | --- | --- |
94
- | `enableSorting` | No sort indicator and no sort menu items. |
95
- | `enableColumnFilter` | No filter menu item. Excluded from the filter panel column list. |
201
+ | `enableSorting` | No sort indicator, no sort menu items, no click-to-sort. |
202
+ | `enableColumnFilter` | No filter menu item. Excluded from the filter panel's column list. |
96
203
  | `enableHiding` | No hide menu item. Checkbox disabled in the column manager. |
97
204
  | `enablePinning` | No pin menu items. |
98
205
  | `enableResizing` | The divider is displayed but cannot be dragged. |
206
+ | `enableGrouping` | No "Group by" menu item. |
99
207
 
100
- `meta.enableOrdering: false` belongs to the same set and removes the column's
101
- header dragging and move menu items. A column inside a header group is never
102
- movable whatever it says, because `columnOrder` sequences leaf columns.
208
+ `meta.enableOrdering: false` belongs to the same set. A column whose menu has no
209
+ remaining items renders no menu button and takes no right-click, so the
210
+ browser's own menu comes up there instead.
103
211
 
104
- A column whose menu has no remaining items renders no menu button.
212
+ ## The generated lanes
105
213
 
106
- ## Checkbox column
214
+ The grid prepends and appends lanes of its own, in this order: row number,
215
+ checkbox, tree, details, your columns, edit. Each appears only when its feature
216
+ asks for it.
107
217
 
108
- Unless `enableRowSelection` is `false` or `rowSelectionMode` is `"row"`, a column
109
- with the id `SELECT_COLUMN_ID` is added as the first column and pinned to the
110
- left. It is listed as "Checkbox selection" in the column manager and can be
111
- hidden like any other column. It has no column menu and cannot be sorted,
112
- filtered, resized, re-pinned or moved.
218
+ | Lane | Id | Appears when |
219
+ | --- | --- | --- |
220
+ | Row number | `ROW_NUMBER_COLUMN_ID` | `enableRowNumbers: true` |
221
+ | Checkbox | `SELECT_COLUMN_ID` | Selection is on and the mode has checkboxes |
222
+ | Tree | `GROUP_COLUMN_ID` | A column is grouped |
223
+ | Details | `DETAILS_COLUMN_ID` | `renderDetails` is set |
224
+ | Edit | `EDIT_COLUMN_ID` | Row mode, `onRowDelete`, or batch with `onEditCommitBatch` |
113
225
 
114
- Because it cannot be moved, it also anchors the left pinned region: no column
115
- can be placed in front of it.
226
+ They are structural: fixed width, no column menu, and they cannot be sorted,
227
+ filtered, resized, re-pinned or moved. The checkbox lane anchors the left pinned
228
+ region, so no column can be placed in front of it. `isControlColumn(column)`
229
+ identifies them.
116
230
 
117
- ## Filtering
231
+ ## Common mistakes
118
232
 
119
- All columns share one filter function. The operator lives in the filter value
120
- rather than being selected through `filterFn`:
233
+ ### CRITICAL Setting `size` to control width
121
234
 
122
- ```ts
123
- type TMDataGridFilterValue = {
124
- operator: TMDataGridFilterOperator;
125
- value: string;
126
- };
127
- ```
235
+ `size` is only applied once the column becomes fixed by resizing or pinning. On
236
+ a fluid column it is ignored - the track is `minmax(minSize, flex fr)` - so a
237
+ column given `size: 200` renders at whatever the flex share works out to, and
238
+ the number looks like it did nothing.
128
239
 
129
- The filter model is therefore plain JSON and can be forwarded to a server without
130
- transformation. See the `server-side` skill.
240
+ Wrong:
131
241
 
132
- ### Operators
242
+ ```tsx
243
+ columnHelper.accessor("email", { header: "Email", size: 200 });
244
+ ```
133
245
 
134
- | Operator | Label | Column type |
135
- | --- | --- | --- |
136
- | `contains` | contains | `string` |
137
- | `equals` | equals | `string`, `number` |
138
- | `notEquals` | does not equal | `string`, `number` |
139
- | `startsWith` | starts with | `string` |
140
- | `endsWith` | ends with | `string` |
141
- | `greaterThan` | is greater than | `number` |
142
- | `greaterThanOrEqual` | is greater than or equal to | `number` |
143
- | `lessThan` | is less than | `number` |
144
- | `lessThanOrEqual` | is less than or equal to | `number` |
145
- | `isEmpty` | is empty | `string`, `number` |
146
- | `isNotEmpty` | is not empty | `string`, `number` |
147
-
148
- `meta.type` selects the list. String comparisons are case-insensitive.
149
- `FILTER_OPERATOR_LABELS` maps operators to their labels.
150
-
151
- To give a column its own matching logic, set `filterFn` on the column definition.
152
- The grid only provides `"tmDataGrid"` as the default.
246
+ Correct:
153
247
 
154
- ## Common mistakes
248
+ ```tsx
249
+ // A floor plus a share, or minSize === maxSize for a genuinely fixed column.
250
+ columnHelper.accessor("email", {
251
+ header: "Email",
252
+ minSize: 200,
253
+ meta: { flex: 2 },
254
+ });
255
+ ```
256
+
257
+ Source: `src/docs/column-layout.md` (Sizing).
155
258
 
156
- ### Component header without meta.label
259
+ ### CRITICAL A component header without `meta.label`
157
260
 
158
- `getColumnLabel(column)` falls back to a *string* header, then the column id.
261
+ `getColumnLabel(column)` falls back to a *string* header, then to the column id.
159
262
  When `header` is a component there is no string to fall back to, so the column
160
- manager and column menus show the raw id (`"fullName"`) instead of a name.
263
+ manager, the filter panel and every column menu show the raw id.
264
+
265
+ Wrong:
161
266
 
162
267
  ```tsx
163
- // Wrong — menus show "fullName".
164
268
  columnHelper.accessor("fullName", { header: () => <Icon /> });
269
+ ```
270
+
271
+ Correct:
165
272
 
166
- // Right.
273
+ ```tsx
167
274
  columnHelper.accessor("fullName", {
168
275
  header: () => <Icon />,
169
276
  meta: { label: "Full name" },
170
277
  });
171
278
  ```
172
279
 
173
- ### Treating an empty filter as no filter
280
+ Source: `src/tmdatagrid/core/columnUtils.ts`.
281
+
282
+ ### HIGH A numeric column without `meta.type`
283
+
284
+ `getColumnType(column)` defaults to `"string"`, so a numeric column that omits
285
+ `meta: { type: "number" }` offers only the string operators, and comparisons run
286
+ as text - `"9"` above `"10"`. The column still sorts and filters, which is why
287
+ it is easy to miss.
288
+
289
+ Source: `src/tmdatagrid/core/filterOperators.ts`.
174
290
 
175
- A filter with an empty value stays in state so the panel keeps showing its row
176
- while the user types. It matches all rows and does not light up the header
177
- indicator. Test with `isFilterActive(value)` rather than checking for presence:
291
+ ### HIGH Expecting a move across pinned regions to work
178
292
 
179
- ```ts
180
- import { isFilterActive } from "@jielga/tmdatagrid";
293
+ `moveColumn` and header dragging are no-ops across regions, silently. A column
294
+ pinned left cannot be dropped in the centre until it is unpinned, and code that
295
+ assumes the move happened goes on to read an order that never changed.
181
296
 
182
- const active = columnFilters.filter((filter) => isFilterActive(filter.value));
297
+ Correct:
298
+
299
+ ```tsx
300
+ table.getColumn("salary")?.pin(false);
301
+ moveColumn({ table, columnId: "salary", targetId: "age", side: "before" });
183
302
  ```
184
303
 
185
- ### Numeric operators on a column without meta.type
304
+ Source: `src/docs/column-layout.md` (Regions).
186
305
 
187
- `getColumnType(column)` defaults to `"string"`, so a numeric column that omits
188
- `meta: { type: "number" }` offers only the string operators — `greaterThan` and
189
- the other comparisons never appear in the panel, and comparisons run as text.
306
+ ### HIGH Reaching for the v8 name of a v9 option
307
+
308
+ TanStack v9 renamed the column comparator to `sortFn`. `sortingFn` is not an
309
+ error the compiler catches in every position - it is simply an unknown key on
310
+ the column definition, so the column keeps its automatic comparator and the
311
+ custom ordering never appears.
312
+
313
+ Wrong:
190
314
 
191
- ### Setting size to control width
315
+ ```tsx
316
+ columnHelper.accessor("priority", { header: "Priority", sortingFn: byRank });
317
+ ```
318
+
319
+ Correct:
320
+
321
+ ```tsx
322
+ columnHelper.accessor("priority", { header: "Priority", sortFn: byRank });
323
+ ```
192
324
 
193
- `size` is only applied once the column becomes fixed by resizing or pinning.
194
- On a fluid column it is ignored; the track is `minmax(minSize, flex fr)`. Use
195
- `minSize` for a floor and `meta.flex` for the share, or `minSize === maxSize`
196
- for a genuinely fixed column.
325
+ Source: `@tanstack/table-core` `rowSortingFeature.types.d.ts`, and
326
+ `src/tmdatagrid/useTMDataGrid.tsx` (the registered `sortFns`).
327
+
328
+ ### MEDIUM Autosize measured against the whole data set
329
+
330
+ Autosizing fits the **mounted** rows plus overscan, not every row, because
331
+ virtualization means the rest have no DOM to measure. A column autosized at the
332
+ top of a long list can be too narrow for a value further down.
333
+
334
+ Source: `src/docs/column-layout.md` (Autosizing).
335
+
336
+ ### MEDIUM Reordering a column inside a header group
337
+
338
+ `columnOrder` sequences leaf columns, so moving one out of its group would leave
339
+ the group header spanning columns that no longer belong to it. Grouped-header
340
+ columns are therefore immovable in both directions, whatever `meta.enableOrdering`
341
+ says.
342
+
343
+ Source: `src/docs/column-layout.md` (Regions).
344
+
345
+ ## Reference
346
+
347
+ | Name | Kind | Type | Default | What it does |
348
+ | --- | --- | --- | --- | --- |
349
+ | `createTMDataGridColumnHelper` | Export | `<TData>() => helper` | – | The typed column helper. |
350
+ | `minSize` / `maxSize` / `size` | Column options | `number` | `80` / – / – | Width bounds, and the fixed width once one applies. |
351
+ | `enableSorting` · `enableColumnFilter` · `enableHiding` · `enablePinning` · `enableResizing` · `enableGrouping` | Column options | `boolean` | `true` | Per-column switches, each removing its interface. |
352
+ | `enableColumnOrdering` | Option | `boolean` | `true` | Header dragging and the move menu items. Grid-defined. |
353
+ | `enableMultiSort` · `maxMultiSortColCount` · `isMultiSortEvent` | Table options | – | Shift held | Multi-column sorting. |
354
+ | `sortFn` | Column option | name or `(rowA, rowB, columnId) => number` | `"auto"` | The comparator for one column. Not v8's `sortingFn`. |
355
+ | `initialState.columnOrder` · `.columnPinning` · `.columnVisibility` · `.columnSizing` | Table options | – | – | Layout at mount. Settings slices, persisted under `settingsKey`. |
356
+ | `initialState.sorting` | Table option | `Array<{ id, desc }>` | `[]` | Sort at mount. A data slice, persisted under `dataKey`. |
357
+ | `resetSettings` | Hook return | `() => void` | – | Clears visibility, order, pinning and widths. |
358
+ | `moveColumn` | Export | `({ table, columnId, targetId, side }) => void` | – | Moves a column beside another. |
359
+ | `moveColumnByStep` | Export | `({ table, columnId, direction }) => void` | – | Moves it one place. |
360
+ | `getStepTargetColumn` | Export | `(args) => Column \| null` | – | What a step would swap with, or `null` at a region edge. |
361
+ | `getColumnRegion` | Export | `(column) => "left" \| "center" \| "right"` | – | Which pinned region a column is in. |
362
+ | `isColumnReorderable` | Export | `(column, features) => boolean` | – | Whether this column may move at all. |
363
+ | `autosizeColumn` | Export | `({ table, columnId, container }) => void` | – | Fits a column to its mounted content. |
364
+ | `measureColumnContentWidth` | Export | `(args) => number` | – | The measurement behind it. |
365
+ | `getColumnLabel` · `getColumnType` · `getColumnDefaultOperator` · `isControlColumn` | Exports | – | – | What the chrome reads off a column. |
366
+ | `SELECT_COLUMN_ID` · `GROUP_COLUMN_ID` · `DETAILS_COLUMN_ID` · `EDIT_COLUMN_ID` · `ROW_NUMBER_COLUMN_ID` | Exports | ids | – | The generated lanes. |
367
+ | `TMDataGrid.ColumnsButton` · `TMDataGrid.ColumnsPanel` | Components | – | – | Manage columns, and Reset layout. |
368
+
369
+ See also: the `filtering` skill for operators and filter controls, the `editing`
370
+ skill for the editing meta fields, and the `grouping` skill for what grouping
371
+ does to a column.