@tanstack/table-core 9.0.0-beta.56 → 9.0.0-beta.58
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/dist/core/row-models/createCoreRowModel.js +5 -1
- package/dist/features/cell-selection/cellSelectionFeature.d.ts +9 -0
- package/dist/features/cell-selection/cellSelectionFeature.js +117 -0
- package/dist/features/cell-selection/cellSelectionFeature.types.d.ts +273 -0
- package/dist/features/cell-selection/cellSelectionFeature.utils.d.ts +288 -0
- package/dist/features/cell-selection/cellSelectionFeature.utils.js +732 -0
- package/dist/features/row-aggregation/rowAggregationFeature.types.d.ts +7 -7
- package/dist/features/stockFeatures.d.ts +3 -1
- package/dist/features/stockFeatures.js +3 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +2 -1
- package/dist/static-functions.d.ts +2 -1
- package/dist/static-functions.js +2 -1
- package/dist/types/Cell.d.ts +4 -2
- package/dist/types/Column.d.ts +2 -2
- package/dist/types/ColumnDef.d.ts +10 -8
- package/dist/types/Row.d.ts +2 -2
- package/dist/types/RowModelFns.d.ts +3 -3
- package/dist/types/Table.d.ts +3 -1
- package/dist/types/TableOptions.d.ts +6 -4
- package/dist/types/TableState.d.ts +3 -1
- package/package.json +1 -1
- package/skills/aggregation/SKILL.md +2 -2
- package/skills/api-not-found/SKILL.md +1 -1
- package/skills/cell-selection/SKILL.md +180 -0
- package/skills/client-vs-server/SKILL.md +1 -1
- package/skills/column-faceting/SKILL.md +1 -1
- package/skills/column-filtering/SKILL.md +1 -1
- package/skills/column-ordering/SKILL.md +1 -1
- package/skills/column-pinning/SKILL.md +1 -1
- package/skills/column-resizing/SKILL.md +1 -1
- package/skills/column-sizing/SKILL.md +1 -1
- package/skills/column-visibility/SKILL.md +1 -1
- package/skills/core/SKILL.md +1 -1
- package/skills/custom-features/SKILL.md +1 -1
- package/skills/expanding/SKILL.md +1 -1
- package/skills/global-filtering/SKILL.md +1 -1
- package/skills/grouping/SKILL.md +1 -1
- package/skills/migrate-v8-to-v9/SKILL.md +1 -1
- package/skills/pagination/SKILL.md +1 -1
- package/skills/row-pinning/SKILL.md +1 -1
- package/skills/row-selection/SKILL.md +1 -1
- package/skills/sorting/SKILL.md +1 -1
- package/skills/table-features/SKILL.md +1 -1
- package/skills/typescript/SKILL.md +1 -1
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cell-selection
|
|
3
|
+
description: >
|
|
4
|
+
Select rectangular cell ranges with cellSelectionFeature: two-corner range state keyed by row and column id, mousedown/mouseenter handlers, selection edges, render-order resolution under pinning, and autoResetCellSelection. Load when ranges widen unexpectedly after sorting or column reordering, when a drag re-renders the whole table, or when building copy-to-clipboard from a selection.
|
|
5
|
+
metadata:
|
|
6
|
+
{
|
|
7
|
+
type: sub-skill,
|
|
8
|
+
library: '@tanstack/table-core',
|
|
9
|
+
library_version: '9.0.0-beta.58',
|
|
10
|
+
}
|
|
11
|
+
requires: ['core', 'table-features']
|
|
12
|
+
sources:
|
|
13
|
+
- 'TanStack/table:docs/framework/react/guide/cell-selection.md'
|
|
14
|
+
- 'TanStack/table:packages/table-core/src/features/cell-selection'
|
|
15
|
+
- 'TanStack/table:examples/react/cell-selection'
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
This skill builds on `core` and `table-features`. `cellSelection` is an array of rectangles, each stored as two corner cells identified by row and column id. It is not a per-cell map, and it is not positional.
|
|
19
|
+
|
|
20
|
+
## Setup
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { cellSelectionFeature, tableFeatures } from '@tanstack/table-core'
|
|
24
|
+
|
|
25
|
+
type Person = { id: string; name: string }
|
|
26
|
+
export const features = tableFeatures({ cellSelectionFeature })
|
|
27
|
+
export const options = {
|
|
28
|
+
getRowId: (row: Person) => row.id,
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
State shape:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
type CellSelectionRange = {
|
|
36
|
+
anchorRowId: string
|
|
37
|
+
anchorColumnId: string
|
|
38
|
+
focusRowId: string
|
|
39
|
+
focusColumnId: string
|
|
40
|
+
}
|
|
41
|
+
type CellSelectionState = Array<CellSelectionRange>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The `anchor` corner stays put; the `focus` corner moves during a drag or Shift-extend. Two corners are what make Shift-extend possible, and they keep a drag across thousands of cells to a two-field write.
|
|
45
|
+
|
|
46
|
+
## Core Patterns
|
|
47
|
+
|
|
48
|
+
### Bind both mouse handlers
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
const onMouseDown = cell.getSelectionStartHandler()
|
|
52
|
+
const onMouseEnter = cell.getSelectionExtendHandler()
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The start handler attaches its own document-level `mouseup` listener and removes it when the drag ends, so a pointer released outside the table still finishes correctly. Pass a document explicitly (`cell.getSelectionStartHandler(iframeDocument)`) only when the table renders into another document.
|
|
56
|
+
|
|
57
|
+
### Read the selection
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
const count = table.getSelectedCellCount()
|
|
61
|
+
const grids = table.getSelectedCellRangesData() // [range][row][column]
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Expansion APIs are memoized and pull-based, so a table that only highlights cells never pays to enumerate a large selection.
|
|
65
|
+
|
|
66
|
+
### Draw the outline from edges
|
|
67
|
+
|
|
68
|
+
`cell.getSelectionEdges()` marks a side `true` when the neighbouring cell in that direction is not selected, which yields one continuous outline around a union of rectangles. All sides are `false` when the cell is not selected.
|
|
69
|
+
|
|
70
|
+
### Drive keyboard navigation externally
|
|
71
|
+
|
|
72
|
+
The feature ships no keydown handling. Call `table.moveCellSelection(direction)`, `table.extendCellSelection(direction)`, `table.setFocusedCell(rowId, columnId)`, `table.selectAllCells()`, and `table.resetCellSelection(true)` from a hotkey library such as `@tanstack/react-hotkeys`, scoped to the grid element rather than the document.
|
|
73
|
+
|
|
74
|
+
## Common Mistakes
|
|
75
|
+
|
|
76
|
+
### [HIGH] Expecting a per-cell selection map
|
|
77
|
+
|
|
78
|
+
Wrong: `const isSelected = table.state.cellSelection[cell.id]`
|
|
79
|
+
|
|
80
|
+
Correct: `const isSelected = cell.getIsSelected()`
|
|
81
|
+
|
|
82
|
+
`cellSelection` holds rectangles, not cell keys. Membership is resolved by comparing the cell's row and column index against the memoized bounds.
|
|
83
|
+
|
|
84
|
+
Source: `packages/table-core/src/features/cell-selection/cellSelectionFeature.types.ts`
|
|
85
|
+
|
|
86
|
+
### [HIGH] Assuming a range is frozen to the cells it originally covered
|
|
87
|
+
|
|
88
|
+
Ranges are anchored to corner ids, so sorting, filtering, and column reordering keep the corners and recompute what sits between them. A range can therefore widen onto columns or rows the user never selected. Reset in userland when the product needs stricter behavior:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
// after a column reorder or pin
|
|
92
|
+
table.resetCellSelection(true)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Hiding a column that a corner sits on makes the range inert rather than deleting it; it returns when the column is shown again.
|
|
96
|
+
|
|
97
|
+
Source: `docs/framework/react/guide/cell-selection.md#how-ranges-survive-table-changes`
|
|
98
|
+
|
|
99
|
+
### [HIGH] Binding only mousedown and expecting drag
|
|
100
|
+
|
|
101
|
+
Wrong:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
const props = { onMouseDown: cell.getSelectionStartHandler() }
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Correct:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
const props = {
|
|
111
|
+
onMouseDown: cell.getSelectionStartHandler(),
|
|
112
|
+
onMouseEnter: cell.getSelectionExtendHandler(),
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Without the extend handler a drag selects only the origin cell. Do not add a `mouseup` binding; the start handler already owns one.
|
|
117
|
+
|
|
118
|
+
Source: `examples/react/cell-selection`
|
|
119
|
+
|
|
120
|
+
### [HIGH] Deriving column position from column definition order
|
|
121
|
+
|
|
122
|
+
Wrong: `const index = column.getIndex()`
|
|
123
|
+
|
|
124
|
+
Correct: `const isSelected = cell.getIsSelected()`
|
|
125
|
+
|
|
126
|
+
Cells render start-pinned first, then center, then end. `getVisibleLeafColumns()` and `column.getIndex()` are not pinning-reordered, so indexing a selection against them makes a rectangle visually scattered as soon as a column is pinned. The feature resolves its own render-order index map; use the cell APIs rather than recomputing membership.
|
|
127
|
+
|
|
128
|
+
Source: `packages/table-core/src/features/cell-selection/cellSelectionFeature.utils.ts`
|
|
129
|
+
|
|
130
|
+
### [HIGH] Re-rendering every cell on each drag update
|
|
131
|
+
|
|
132
|
+
Wrong: one subscription wrapping the whole `<tbody>`.
|
|
133
|
+
|
|
134
|
+
Correct: one subscription per row, with a selector returning only what changes that row's appearance.
|
|
135
|
+
|
|
136
|
+
A drag writes state on every cell boundary crossed. A table-wide subscription reconciles every cell each time. Subscribe per row against `table.atoms.cellSelection` and derive a key from `table.getCellSelectionBounds()` (memoized, so it computes once per change) covering the row itself plus the rows above and below, which decide its top and bottom edges.
|
|
137
|
+
|
|
138
|
+
Source: `docs/framework/react/guide/cell-selection.md#performance-with-tablesubscribe`
|
|
139
|
+
|
|
140
|
+
### [MEDIUM] Drawing selection borders on a border-collapse table
|
|
141
|
+
|
|
142
|
+
Wrong: `.cell-selected { border: 2px solid blue }`
|
|
143
|
+
|
|
144
|
+
Correct: `.cell-selected { box-shadow: inset 0 0 0 2px blue }`
|
|
145
|
+
|
|
146
|
+
On a `border-collapse` table a thicker border widens the shared grid line, so rows change height as cells become selected. Box-shadow never affects layout.
|
|
147
|
+
|
|
148
|
+
Source: `examples/react/cell-selection/src/index.css`
|
|
149
|
+
|
|
150
|
+
### [MEDIUM] Expecting a clipboard string from the table
|
|
151
|
+
|
|
152
|
+
Wrong: `navigator.clipboard.writeText(table.getSelectedCellsAsTsv())`
|
|
153
|
+
|
|
154
|
+
Correct: `navigator.clipboard.writeText(toTsv(table.getSelectedCellRangesData()))`
|
|
155
|
+
|
|
156
|
+
The table returns raw values only. The delimiter, the representation of `null`, and quoting rules are application decisions, so serialization is userland. Quote any field containing a tab, newline, or quote, or a pasted spreadsheet gains phantom columns.
|
|
157
|
+
|
|
158
|
+
Source: `docs/framework/react/guide/cell-selection.md#copying-a-selection`
|
|
159
|
+
|
|
160
|
+
### [MEDIUM] Persisting a selection and expecting drag state with it
|
|
161
|
+
|
|
162
|
+
`cellSelection` is safe to persist because drag session state is deliberately non-reactive instance data, not part of the slice. Do not add an `isSelecting` field to the persisted state; a stored `true` would rehydrate into a drag that hovering extends and nothing ever ends.
|
|
163
|
+
|
|
164
|
+
Source: `packages/table-core/src/features/cell-selection/cellSelectionFeature.types.ts`
|
|
165
|
+
|
|
166
|
+
### [MEDIUM] Fighting the automatic reset on data change
|
|
167
|
+
|
|
168
|
+
Selection resets to `initialState.cellSelection` whenever `data` changes, because new data can invalidate the row ids a range points at or silently re-select cells when ids are reused. Opt out deliberately:
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
export const keepAcrossDataChanges = { autoResetCellSelection: false }
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
`autoResetAll` overrides this option.
|
|
175
|
+
|
|
176
|
+
Source: `packages/table-core/src/features/cell-selection/cellSelectionFeature.ts`
|
|
177
|
+
|
|
178
|
+
## API Discovery
|
|
179
|
+
|
|
180
|
+
Inspect `node_modules/@tanstack/table-core/dist/features/cell-selection/` for `CellSelectionRange`, `CellSelectionState`, `CellSelectionBounds`, `CellSelectionEdges`, the enablement and `is*Event` options, and the cell and table instance APIs.
|
package/skills/core/SKILL.md
CHANGED
|
@@ -5,7 +5,7 @@ description: >
|
|
|
5
5
|
metadata:
|
|
6
6
|
type: sub-skill
|
|
7
7
|
library: '@tanstack/table-core'
|
|
8
|
-
library_version: '9.0.0-beta.
|
|
8
|
+
library_version: '9.0.0-beta.58'
|
|
9
9
|
requires: ['core', 'table-features', 'typescript']
|
|
10
10
|
sources:
|
|
11
11
|
- 'TanStack/table:docs/framework/react/guide/custom-features.md'
|
package/skills/grouping/SKILL.md
CHANGED
|
@@ -5,7 +5,7 @@ description: >
|
|
|
5
5
|
metadata:
|
|
6
6
|
type: lifecycle
|
|
7
7
|
library: '@tanstack/table-core'
|
|
8
|
-
library_version: '9.0.0-beta.
|
|
8
|
+
library_version: '9.0.0-beta.58'
|
|
9
9
|
requires: ['core', 'table-features', 'typescript']
|
|
10
10
|
sources:
|
|
11
11
|
- 'TanStack/table:docs/framework/react/guide/migrating.md'
|
package/skills/sorting/SKILL.md
CHANGED