@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.
Files changed (45) hide show
  1. package/dist/core/row-models/createCoreRowModel.js +5 -1
  2. package/dist/features/cell-selection/cellSelectionFeature.d.ts +9 -0
  3. package/dist/features/cell-selection/cellSelectionFeature.js +117 -0
  4. package/dist/features/cell-selection/cellSelectionFeature.types.d.ts +273 -0
  5. package/dist/features/cell-selection/cellSelectionFeature.utils.d.ts +288 -0
  6. package/dist/features/cell-selection/cellSelectionFeature.utils.js +732 -0
  7. package/dist/features/row-aggregation/rowAggregationFeature.types.d.ts +7 -7
  8. package/dist/features/stockFeatures.d.ts +3 -1
  9. package/dist/features/stockFeatures.js +3 -1
  10. package/dist/index.d.ts +4 -2
  11. package/dist/index.js +2 -1
  12. package/dist/static-functions.d.ts +2 -1
  13. package/dist/static-functions.js +2 -1
  14. package/dist/types/Cell.d.ts +4 -2
  15. package/dist/types/Column.d.ts +2 -2
  16. package/dist/types/ColumnDef.d.ts +10 -8
  17. package/dist/types/Row.d.ts +2 -2
  18. package/dist/types/RowModelFns.d.ts +3 -3
  19. package/dist/types/Table.d.ts +3 -1
  20. package/dist/types/TableOptions.d.ts +6 -4
  21. package/dist/types/TableState.d.ts +3 -1
  22. package/package.json +1 -1
  23. package/skills/aggregation/SKILL.md +2 -2
  24. package/skills/api-not-found/SKILL.md +1 -1
  25. package/skills/cell-selection/SKILL.md +180 -0
  26. package/skills/client-vs-server/SKILL.md +1 -1
  27. package/skills/column-faceting/SKILL.md +1 -1
  28. package/skills/column-filtering/SKILL.md +1 -1
  29. package/skills/column-ordering/SKILL.md +1 -1
  30. package/skills/column-pinning/SKILL.md +1 -1
  31. package/skills/column-resizing/SKILL.md +1 -1
  32. package/skills/column-sizing/SKILL.md +1 -1
  33. package/skills/column-visibility/SKILL.md +1 -1
  34. package/skills/core/SKILL.md +1 -1
  35. package/skills/custom-features/SKILL.md +1 -1
  36. package/skills/expanding/SKILL.md +1 -1
  37. package/skills/global-filtering/SKILL.md +1 -1
  38. package/skills/grouping/SKILL.md +1 -1
  39. package/skills/migrate-v8-to-v9/SKILL.md +1 -1
  40. package/skills/pagination/SKILL.md +1 -1
  41. package/skills/row-pinning/SKILL.md +1 -1
  42. package/skills/row-selection/SKILL.md +1 -1
  43. package/skills/sorting/SKILL.md +1 -1
  44. package/skills/table-features/SKILL.md +1 -1
  45. package/skills/typescript/SKILL.md +1 -1
@@ -1,5 +1,6 @@
1
1
  import { makeObjectMap, tableMemo } from "../../utils.js";
2
2
  import { constructRow } from "../rows/constructRow.js";
3
+ import { table_autoResetCellSelection } from "../../features/cell-selection/cellSelectionFeature.utils.js";
3
4
  import { table_autoResetPageIndex } from "../../features/row-pagination/rowPaginationFeature.utils.js";
4
5
 
5
6
  //#region src/core/row-models/createCoreRowModel.ts
@@ -16,7 +17,10 @@ function createCoreRowModel() {
16
17
  fnName: "table.getCoreRowModel",
17
18
  memoDeps: () => [table.options.data],
18
19
  fn: () => _createCoreRowModel(table, table.options.data),
19
- onAfterUpdate: () => table_autoResetPageIndex(table)
20
+ onAfterUpdate: () => {
21
+ table_autoResetPageIndex(table);
22
+ table_autoResetCellSelection(table);
23
+ }
20
24
  });
21
25
  };
22
26
  }
@@ -0,0 +1,9 @@
1
+ import { TableFeature } from "../../types/TableFeatures.js";
2
+
3
+ //#region src/features/cell-selection/cellSelectionFeature.d.ts
4
+ /**
5
+ * Feature that adds spreadsheet-style cell range selection state and APIs.
6
+ */
7
+ declare const cellSelectionFeature: TableFeature;
8
+ //#endregion
9
+ export { cellSelectionFeature };
@@ -0,0 +1,117 @@
1
+ import { assignPrototypeAPIs, assignTableAPIs, callMemoOrStaticFn, makeStateUpdater } from "../../utils.js";
2
+ import { cell_getCanSelect, cell_getIsFocused, cell_getIsSelected, cell_getSelectionEdges, cell_getSelectionExtendHandler, cell_getSelectionStartHandler, cell_getTabIndex, getDefaultCellSelectionState, table_autoResetCellSelection, table_extendCellSelection, table_getCellSelectionBounds, table_getCellSelectionColumnIds, table_getCellSelectionColumnIndexes, table_getCellSelectionRowIds, table_getFocusedCell, table_getSelectedCellCount, table_getSelectedCellIds, table_getSelectedCellRangesData, table_moveCellSelection, table_resetCellSelection, table_selectAllCells, table_selectCellRange, table_setCellSelection, table_setFocusedCell } from "./cellSelectionFeature.utils.js";
3
+
4
+ //#region src/features/cell-selection/cellSelectionFeature.ts
5
+ /**
6
+ * Feature that adds spreadsheet-style cell range selection state and APIs.
7
+ */
8
+ const cellSelectionFeature = {
9
+ initTableInstanceData: (table) => {
10
+ table._isSelectingCells = false;
11
+ },
12
+ resetTableInstanceData: (table) => {
13
+ table._isSelectingCells = false;
14
+ },
15
+ getInitialState: (initialState) => {
16
+ return {
17
+ cellSelection: getDefaultCellSelectionState(),
18
+ ...initialState
19
+ };
20
+ },
21
+ getDefaultTableOptions: (table) => {
22
+ return {
23
+ onCellSelectionChange: makeStateUpdater("cellSelection", table),
24
+ autoResetCellSelection: true,
25
+ enableCellSelection: true,
26
+ enableCellRangeSelection: true,
27
+ enableMultiCellRangeSelection: true,
28
+ enableCellSelectionDrag: true,
29
+ isCellRangeSelectionEvent: (event) => {
30
+ const rangeEvent = event;
31
+ return Boolean(rangeEvent.shiftKey || rangeEvent.nativeEvent?.shiftKey);
32
+ },
33
+ isMultiCellRangeSelectionEvent: (event) => {
34
+ const multiEvent = event;
35
+ return Boolean(multiEvent.ctrlKey || multiEvent.metaKey || multiEvent.nativeEvent?.ctrlKey || multiEvent.nativeEvent?.metaKey);
36
+ }
37
+ };
38
+ },
39
+ assignCellPrototype: (prototype, table) => {
40
+ assignPrototypeAPIs("cellSelectionFeature", prototype, table, {
41
+ cell_getCanSelect: { fn: (cell) => cell_getCanSelect(cell) },
42
+ cell_getIsSelected: { fn: (cell) => cell_getIsSelected(cell) },
43
+ cell_getIsFocused: { fn: (cell) => cell_getIsFocused(cell) },
44
+ cell_getTabIndex: { fn: (cell) => cell_getTabIndex(cell) },
45
+ cell_getSelectionEdges: { fn: (cell) => cell_getSelectionEdges(cell) },
46
+ cell_getSelectionStartHandler: { fn: (cell, contextDocument) => cell_getSelectionStartHandler(cell, contextDocument) },
47
+ cell_getSelectionExtendHandler: { fn: (cell) => cell_getSelectionExtendHandler(cell) }
48
+ });
49
+ },
50
+ constructTableAPIs: (table) => {
51
+ assignTableAPIs("cellSelectionFeature", table, {
52
+ table_setCellSelection: { fn: (updater) => table_setCellSelection(table, updater) },
53
+ table_resetCellSelection: { fn: (defaultState) => table_resetCellSelection(table, defaultState) },
54
+ table_autoResetCellSelection: { fn: () => table_autoResetCellSelection(table) },
55
+ table_getCellSelectionColumnIndexes: {
56
+ fn: () => table_getCellSelectionColumnIndexes(table),
57
+ memoDeps: () => [
58
+ table.atoms.columnVisibility?.get(),
59
+ table.atoms.columnOrder?.get(),
60
+ table.atoms.columnPinning?.get(),
61
+ table.atoms.grouping?.get(),
62
+ table.options.columns,
63
+ table.options.groupedColumnMode
64
+ ]
65
+ },
66
+ table_getCellSelectionBounds: {
67
+ fn: () => table_getCellSelectionBounds(table),
68
+ memoDeps: () => [
69
+ table.atoms.cellSelection?.get(),
70
+ table.getRowsInDisplayOrder(),
71
+ callMemoOrStaticFn(table, "getCellSelectionColumnIndexes", table_getCellSelectionColumnIndexes)
72
+ ]
73
+ },
74
+ table_selectCellRange: { fn: (range, opts) => table_selectCellRange(table, range, opts) },
75
+ table_selectAllCells: { fn: () => table_selectAllCells(table) },
76
+ table_setFocusedCell: { fn: (rowId, columnId) => table_setFocusedCell(table, rowId, columnId) },
77
+ table_getFocusedCell: { fn: () => table_getFocusedCell(table) },
78
+ table_moveCellSelection: { fn: (direction) => table_moveCellSelection(table, direction) },
79
+ table_extendCellSelection: { fn: (direction) => table_extendCellSelection(table, direction) },
80
+ table_getSelectedCellIds: {
81
+ fn: () => table_getSelectedCellIds(table),
82
+ memoDeps: () => [
83
+ callMemoOrStaticFn(table, "getCellSelectionBounds", table_getCellSelectionBounds),
84
+ table.getRowsInDisplayOrder(),
85
+ table.options.enableCellSelection
86
+ ]
87
+ },
88
+ table_getSelectedCellRangesData: {
89
+ fn: () => table_getSelectedCellRangesData(table),
90
+ memoDeps: () => [
91
+ callMemoOrStaticFn(table, "getCellSelectionBounds", table_getCellSelectionBounds),
92
+ table.getRowsInDisplayOrder(),
93
+ table.options.enableCellSelection
94
+ ]
95
+ },
96
+ table_getSelectedCellCount: {
97
+ fn: () => table_getSelectedCellCount(table),
98
+ memoDeps: () => [
99
+ callMemoOrStaticFn(table, "getCellSelectionBounds", table_getCellSelectionBounds),
100
+ table.getRowsInDisplayOrder(),
101
+ table.options.enableCellSelection
102
+ ]
103
+ },
104
+ table_getCellSelectionRowIds: {
105
+ fn: () => table_getCellSelectionRowIds(table),
106
+ memoDeps: () => [callMemoOrStaticFn(table, "getCellSelectionBounds", table_getCellSelectionBounds), table.getRowsInDisplayOrder()]
107
+ },
108
+ table_getCellSelectionColumnIds: {
109
+ fn: () => table_getCellSelectionColumnIds(table),
110
+ memoDeps: () => [callMemoOrStaticFn(table, "getCellSelectionBounds", table_getCellSelectionBounds)]
111
+ }
112
+ });
113
+ }
114
+ };
115
+
116
+ //#endregion
117
+ export { cellSelectionFeature };
@@ -0,0 +1,273 @@
1
+ import { CellData, OnChangeFn, RowData, Updater } from "../../types/type-utils.js";
2
+ import { Cell } from "../../types/Cell.js";
3
+ import { TableFeatures } from "../../types/TableFeatures.js";
4
+
5
+ //#region src/features/cell-selection/cellSelectionFeature.types.d.ts
6
+ /**
7
+ * A single rectangular cell selection, stored as its two defining corners.
8
+ *
9
+ * The `anchor` corner stays put while the `focus` corner moves during a
10
+ * shift-extend or a drag, so the pair carries strictly more information than a
11
+ * normalized min/max rectangle would. Corners are stored as flat row and column
12
+ * ids rather than nested objects or a packed `rowId_columnId` key, because
13
+ * `getRowId` is user-supplied and may return ids containing any separator.
14
+ */
15
+ interface CellSelectionRange {
16
+ anchorColumnId: string;
17
+ anchorRowId: string;
18
+ focusColumnId: string;
19
+ focusRowId: string;
20
+ }
21
+ /**
22
+ * The selected rectangles. The last entry is the active one that shift-extend
23
+ * and drag operate on.
24
+ *
25
+ * A bare array, matching `SortingState` and `ColumnFiltersState`. Drag session
26
+ * state deliberately lives outside this slice as non-reactive instance data, so
27
+ * nothing here is transient and the whole slice is safe to persist.
28
+ */
29
+ type CellSelectionState = Array<CellSelectionRange>;
30
+ interface TableState_CellSelection {
31
+ cellSelection: CellSelectionState;
32
+ }
33
+ /**
34
+ * A range resolved into inclusive display-order indexes.
35
+ *
36
+ * Ranges whose corners no longer resolve are omitted rather than clamped, so a
37
+ * range with a filtered-out corner contributes nothing while remaining in state.
38
+ */
39
+ interface CellSelectionBounds {
40
+ maxColumnIndex: number;
41
+ maxRowIndex: number;
42
+ minColumnIndex: number;
43
+ minRowIndex: number;
44
+ }
45
+ /**
46
+ * Which sides of a selected cell sit on the outer boundary of the selection.
47
+ */
48
+ interface CellSelectionEdges {
49
+ bottom: boolean;
50
+ left: boolean;
51
+ right: boolean;
52
+ top: boolean;
53
+ }
54
+ type CellSelectionDirection = 'up' | 'down' | 'left' | 'right';
55
+ interface SelectCellRangeOptions {
56
+ /**
57
+ * Whether the range should be added alongside existing ranges rather than
58
+ * replacing them. Defaults to `false`.
59
+ */
60
+ additive?: boolean;
61
+ }
62
+ interface TableOptions_CellSelection<in out TFeatures extends TableFeatures, in out TData extends RowData> {
63
+ /**
64
+ * Resets cell selection to `initialState.cellSelection` whenever `data`
65
+ * changes. Defaults to `true`.
66
+ *
67
+ * Ranges are stored as row and column ids, so new data would otherwise leave
68
+ * a selection pointing at rows that no longer exist, or silently re-select
69
+ * cells if the new data happens to reuse ids. Set to `false` to keep ranges
70
+ * across data changes, and note `autoResetAll` overrides this.
71
+ */
72
+ autoResetCellSelection?: boolean;
73
+ /**
74
+ * Enables inclusive cell range selection through shift-click and drag.
75
+ * Defaults to `true`.
76
+ */
77
+ enableCellRangeSelection?: boolean;
78
+ /**
79
+ * Allows cells to be selected.
80
+ *
81
+ * Provide a predicate to decide per cell. A column def may also opt out with
82
+ * its own `enableCellSelection: false`. Defaults to `true`.
83
+ */
84
+ enableCellSelection?: boolean | ((cell: Cell<TFeatures, TData, any>) => boolean);
85
+ /**
86
+ * Enables extending a selection by dragging across cells. Defaults to `true`.
87
+ */
88
+ enableCellSelectionDrag?: boolean;
89
+ /**
90
+ * Allows multiple disjoint rectangles to be selected at once. Defaults to
91
+ * `true`.
92
+ */
93
+ enableMultiCellRangeSelection?: boolean;
94
+ /**
95
+ * Determines whether a selection-start event should extend the active range
96
+ * instead of replacing the selection.
97
+ *
98
+ * By default, events with `shiftKey` directly on the event or on
99
+ * `event.nativeEvent` are treated as range-selection events.
100
+ */
101
+ isCellRangeSelectionEvent?: (event: unknown) => boolean;
102
+ /**
103
+ * Determines whether a selection-start event should add a new rectangle
104
+ * alongside the existing ones.
105
+ *
106
+ * By default, events with `ctrlKey` or `metaKey` directly on the event or on
107
+ * `event.nativeEvent` are treated as multi-range events.
108
+ */
109
+ isMultiCellRangeSelectionEvent?: (event: unknown) => boolean;
110
+ /**
111
+ * Called with an updater when cell selection state changes. Pair this with
112
+ * `state.cellSelection` when using external state; external atoms can own the
113
+ * slice without this callback.
114
+ *
115
+ * A drag emits one change per cell crossed. Subscribe to
116
+ * `table.atoms.cellSelection` for finer-grained reads when that matters.
117
+ */
118
+ onCellSelectionChange?: OnChangeFn<CellSelectionState>;
119
+ }
120
+ interface ColumnDef_CellSelection {
121
+ /**
122
+ * Allows cells in this column to be selected. Defaults to `true`.
123
+ */
124
+ enableCellSelection?: boolean;
125
+ }
126
+ interface Cell_CellSelection {
127
+ /**
128
+ * Checks whether this cell can currently be selected.
129
+ */
130
+ getCanSelect: () => boolean;
131
+ /**
132
+ * Checks whether this cell is the active cell, i.e. the anchor of the most
133
+ * recent range.
134
+ */
135
+ getIsFocused: () => boolean;
136
+ /**
137
+ * Checks whether this cell falls inside any selected range.
138
+ */
139
+ getIsSelected: () => boolean;
140
+ /**
141
+ * Returns which sides of this cell sit on the outer boundary of the
142
+ * selection, for rendering a spreadsheet-style outline without each cell
143
+ * inspecting its neighbours.
144
+ *
145
+ * All sides are `false` when the cell is not selected.
146
+ */
147
+ getSelectionEdges: () => CellSelectionEdges;
148
+ /**
149
+ * Creates a handler that extends the active range to this cell while a drag
150
+ * is in progress. Bind it to `mouseenter`.
151
+ *
152
+ * The handler no-ops unless a drag is open, and skips redundant writes when
153
+ * the active range already focuses this cell.
154
+ */
155
+ getSelectionExtendHandler: () => (event: unknown) => void;
156
+ /**
157
+ * Creates a handler that begins a selection at this cell. Bind it to
158
+ * `mousedown`.
159
+ *
160
+ * Pass the original mouse event, or a framework event whose `nativeEvent` is
161
+ * that event, so modifier keys can be detected. The handler attaches its own
162
+ * document-level `mouseup` listener so a drag released outside the table
163
+ * still ends correctly; pass `contextDocument` when the table renders into
164
+ * another document, such as an iframe or popout window.
165
+ */
166
+ getSelectionStartHandler: (contextDocument?: Document) => (event: unknown) => void;
167
+ /**
168
+ * Returns `0` for the focused cell and `-1` otherwise, for roving tabindex.
169
+ */
170
+ getTabIndex: () => number;
171
+ }
172
+ interface Table_CellSelection<in out TFeatures extends TableFeatures, in out TData extends RowData> {
173
+ /**
174
+ * Whether a drag selection is currently open.
175
+ *
176
+ * Non-reactive instance data rather than state: only the mouse handlers read
177
+ * it, nothing renders from it, and keeping it out of the slice means a
178
+ * selection persisted mid-drag cannot rehydrate into a stuck drag.
179
+ *
180
+ * @internal
181
+ */
182
+ _isSelectingCells: boolean;
183
+ /**
184
+ * Schedules a cell selection reset after `data` changes.
185
+ *
186
+ * Honors `autoResetAll` and `autoResetCellSelection`. Called by the core row
187
+ * model; you rarely need to invoke it yourself.
188
+ */
189
+ autoResetCellSelection: () => void;
190
+ /**
191
+ * Extends the active range one step in a direction, keeping its anchor fixed.
192
+ */
193
+ extendCellSelection: (direction: CellSelectionDirection) => void;
194
+ /**
195
+ * Returns the selected ranges resolved into inclusive display-order indexes.
196
+ *
197
+ * This is the memoized cache every per-cell read goes through. Ranges whose
198
+ * corners no longer resolve are omitted.
199
+ */
200
+ getCellSelectionBounds: () => Array<CellSelectionBounds>;
201
+ /**
202
+ * Returns the ids of all columns intersected by the selection.
203
+ */
204
+ getCellSelectionColumnIds: () => Array<string>;
205
+ /**
206
+ * Returns a column id to display-index map for the current column order.
207
+ *
208
+ * Registered so the lookup stays memoized even when `columnOrderingFeature`
209
+ * is absent, since its `getColumnIndexes` static rebuilds on every call.
210
+ *
211
+ * @internal
212
+ */
213
+ getCellSelectionColumnIndexes: () => Record<string, number>;
214
+ /**
215
+ * Returns the ids of all rows intersected by the selection.
216
+ */
217
+ getCellSelectionRowIds: () => Array<string>;
218
+ /**
219
+ * Returns the active cell, i.e. the anchor of the most recent range.
220
+ */
221
+ getFocusedCell: () => Cell<TFeatures, TData, any> | undefined;
222
+ /**
223
+ * Returns the number of selected cells.
224
+ *
225
+ * Computed as rectangle arithmetic for one range. Falls back to enumerating
226
+ * cells for overlapping ranges or a per-cell `enableCellSelection` predicate.
227
+ */
228
+ getSelectedCellCount: () => number;
229
+ /**
230
+ * Returns the unique ids of all selected cells, in row-major order.
231
+ *
232
+ * This expands the selection, so it costs one pass over the selected area.
233
+ * It is memoized and never runs unless called.
234
+ */
235
+ getSelectedCellIds: () => Array<string>;
236
+ /**
237
+ * Returns each selected range's values as a row-major grid.
238
+ *
239
+ * Indexed as `[rangeIndex][rowIndex][columnIndex]`. Serializing this to
240
+ * clipboard text is left to userland, since the delimiter, the null
241
+ * representation, and any quoting rules are application decisions.
242
+ */
243
+ getSelectedCellRangesData: () => Array<Array<Array<unknown>>>;
244
+ /**
245
+ * Moves the selection one step in a direction, collapsing it to a single
246
+ * cell. Columns that cannot be selected are skipped over.
247
+ */
248
+ moveCellSelection: (direction: CellSelectionDirection) => void;
249
+ /**
250
+ * Resets `cellSelection` to `initialState.cellSelection`.
251
+ *
252
+ * Pass `true` to ignore initial state and reset to an empty selection.
253
+ */
254
+ resetCellSelection: (defaultState?: boolean) => void;
255
+ /**
256
+ * Selects every selectable cell in the table as one range.
257
+ */
258
+ selectAllCells: () => void;
259
+ /**
260
+ * Selects a rectangle, replacing the current selection unless `additive`.
261
+ */
262
+ selectCellRange: (range: CellSelectionRange, opts?: SelectCellRangeOptions) => void;
263
+ /**
264
+ * Updates cell selection state with a next value or updater function.
265
+ */
266
+ setCellSelection: (updater: Updater<CellSelectionState>) => void;
267
+ /**
268
+ * Collapses the selection to a single cell at the given coordinates.
269
+ */
270
+ setFocusedCell: (rowId: string, columnId: string) => void;
271
+ }
272
+ //#endregion
273
+ export { CellSelectionBounds, CellSelectionDirection, CellSelectionEdges, CellSelectionRange, CellSelectionState, Cell_CellSelection, ColumnDef_CellSelection, SelectCellRangeOptions, TableOptions_CellSelection, TableState_CellSelection, Table_CellSelection };