@tanstack/table-core 8.9.11 → 8.10.1

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tanstack/table-core",
3
3
  "author": "Tanner Linsley",
4
- "version": "8.9.11",
4
+ "version": "8.10.1",
5
5
  "description": "Headless UI for building powerful tables & datagrids for TS/JS.",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/tanstack/table#readme",
package/src/core/table.ts CHANGED
@@ -99,7 +99,7 @@ export interface CoreInstance<TData extends RowData> {
99
99
  getCoreRowModel: () => RowModel<TData>
100
100
  _getCoreRowModel?: () => RowModel<TData>
101
101
  getRowModel: () => RowModel<TData>
102
- getRow: (id: string) => Row<TData>
102
+ getRow: (id: string, searchAll?: boolean) => Row<TData>
103
103
  _getDefaultColumnDef: () => Partial<ColumnDef<TData, unknown>>
104
104
  _getColumnDefs: () => ColumnDef<TData, unknown>[]
105
105
  _getAllFlatColumnsById: () => Record<string, Column<TData, unknown>>
@@ -213,8 +213,9 @@ export function createTable<TData extends RowData>(
213
213
  getRowModel: () => {
214
214
  return table.getPaginationRowModel()
215
215
  },
216
- getRow: (id: string) => {
217
- const row = table.getRowModel().rowsById[id]
216
+ getRow: (id: string, searchAll?: boolean) => {
217
+ const row = (searchAll ? table.getCoreRowModel() : table.getRowModel())
218
+ .rowsById[id]
218
219
 
219
220
  if (!row) {
220
221
  if (process.env.NODE_ENV !== 'production') {
@@ -311,10 +312,13 @@ export function createTable<TData extends RowData>(
311
312
  _getAllFlatColumnsById: memo(
312
313
  () => [table.getAllFlatColumns()],
313
314
  flatColumns => {
314
- return flatColumns.reduce((acc, column) => {
315
- acc[column.id] = column
316
- return acc
317
- }, {} as Record<string, Column<TData, unknown>>)
315
+ return flatColumns.reduce(
316
+ (acc, column) => {
317
+ acc[column.id] = column
318
+ return acc
319
+ },
320
+ {} as Record<string, Column<TData, unknown>>
321
+ )
318
322
  },
319
323
  {
320
324
  key: process.env.NODE_ENV === 'development' && 'getAllFlatColumnsById',
@@ -13,6 +13,7 @@ export interface ExpandedRow {
13
13
  toggleExpanded: (expanded?: boolean) => void
14
14
  getIsExpanded: () => boolean
15
15
  getCanExpand: () => boolean
16
+ getIsAllParentsExpanded: () => boolean
16
17
  getToggleExpandedHandler: () => () => void
17
18
  }
18
19
 
@@ -210,6 +211,17 @@ export const Expanding: TableFeature = {
210
211
  ((table.options.enableExpanding ?? true) && !!row.subRows?.length)
211
212
  )
212
213
  }
214
+ row.getIsAllParentsExpanded = () => {
215
+ let isFullyExpanded = true
216
+ let currentRow = row
217
+
218
+ while (isFullyExpanded && currentRow.parentId) {
219
+ currentRow = table.getRow(currentRow.parentId, true)
220
+ isFullyExpanded = currentRow.getIsExpanded()
221
+ }
222
+
223
+ return isFullyExpanded
224
+ }
213
225
  row.getToggleExpandedHandler = () => {
214
226
  const canExpand = row.getCanExpand()
215
227
 
@@ -11,25 +11,46 @@ import {
11
11
  import { makeStateUpdater, memo } from '../utils'
12
12
 
13
13
  export type ColumnPinningPosition = false | 'left' | 'right'
14
+ export type RowPinningPosition = false | 'top' | 'bottom'
14
15
 
15
16
  export interface ColumnPinningState {
16
17
  left?: string[]
17
18
  right?: string[]
18
19
  }
19
20
 
21
+ export interface RowPinningState {
22
+ top?: string[]
23
+ bottom?: string[]
24
+ }
25
+
20
26
  export interface ColumnPinningTableState {
21
27
  columnPinning: ColumnPinningState
22
28
  }
23
29
 
30
+ export interface RowPinningTableState {
31
+ rowPinning: RowPinningState
32
+ }
33
+
24
34
  export interface ColumnPinningOptions {
25
35
  onColumnPinningChange?: OnChangeFn<ColumnPinningState>
26
36
  enablePinning?: boolean
37
+ enableColumnPinning?: boolean
38
+ }
39
+
40
+ export interface RowPinningOptions<TData extends RowData> {
41
+ onRowPinningChange?: OnChangeFn<RowPinningState>
42
+ enableRowPinning?: boolean | ((row: Row<TData>) => boolean)
43
+ keepPinnedRows?: boolean
27
44
  }
28
45
 
29
46
  export interface ColumnPinningDefaultOptions {
30
47
  onColumnPinningChange: OnChangeFn<ColumnPinningState>
31
48
  }
32
49
 
50
+ export interface RowPinningDefaultOptions {
51
+ onRowPinningChange: OnChangeFn<RowPinningState>
52
+ }
53
+
33
54
  export interface ColumnPinningColumnDef {
34
55
  enablePinning?: boolean
35
56
  }
@@ -47,6 +68,17 @@ export interface ColumnPinningRow<TData extends RowData> {
47
68
  getRightVisibleCells: () => Cell<TData, unknown>[]
48
69
  }
49
70
 
71
+ export interface RowPinningRow {
72
+ getCanPin: () => boolean
73
+ getIsPinned: () => RowPinningPosition
74
+ getPinnedIndex: () => number
75
+ pin: (
76
+ position: RowPinningPosition,
77
+ includeLeafRows?: boolean,
78
+ includeParentRows?: boolean
79
+ ) => void
80
+ }
81
+
50
82
  export interface ColumnPinningInstance<TData extends RowData> {
51
83
  setColumnPinning: (updater: Updater<ColumnPinningState>) => void
52
84
  resetColumnPinning: (defaultState?: boolean) => void
@@ -56,26 +88,43 @@ export interface ColumnPinningInstance<TData extends RowData> {
56
88
  getCenterLeafColumns: () => Column<TData, unknown>[]
57
89
  }
58
90
 
91
+ export interface RowPinningInstance<TData extends RowData> {
92
+ setRowPinning: (updater: Updater<RowPinningState>) => void
93
+ resetRowPinning: (defaultState?: boolean) => void
94
+ getIsSomeRowsPinned: (position?: RowPinningPosition) => boolean
95
+ _getPinnedRows: (position: 'top' | 'bottom') => Row<TData>[]
96
+ getTopRows: () => Row<TData>[]
97
+ getBottomRows: () => Row<TData>[]
98
+ getCenterRows: () => Row<TData>[]
99
+ }
100
+
59
101
  //
60
102
 
61
- const getDefaultPinningState = (): ColumnPinningState => ({
103
+ const getDefaultColumnPinningState = (): ColumnPinningState => ({
62
104
  left: [],
63
105
  right: [],
64
106
  })
65
107
 
108
+ const getDefaultRowPinningState = (): RowPinningState => ({
109
+ top: [],
110
+ bottom: [],
111
+ })
112
+
66
113
  export const Pinning: TableFeature = {
67
- getInitialState: (state): ColumnPinningTableState => {
114
+ getInitialState: (state): ColumnPinningTableState & RowPinningState => {
68
115
  return {
69
- columnPinning: getDefaultPinningState(),
116
+ columnPinning: getDefaultColumnPinningState(),
117
+ rowPinning: getDefaultRowPinningState(),
70
118
  ...state,
71
119
  }
72
120
  },
73
121
 
74
122
  getDefaultOptions: <TData extends RowData>(
75
123
  table: Table<TData>
76
- ): ColumnPinningDefaultOptions => {
124
+ ): ColumnPinningDefaultOptions & RowPinningDefaultOptions => {
77
125
  return {
78
126
  onColumnPinningChange: makeStateUpdater('columnPinning', table),
127
+ onRowPinningChange: makeStateUpdater('rowPinning', table),
79
128
  }
80
129
  },
81
130
 
@@ -123,7 +172,9 @@ export const Pinning: TableFeature = {
123
172
  return leafColumns.some(
124
173
  d =>
125
174
  (d.columnDef.enablePinning ?? true) &&
126
- (table.options.enablePinning ?? true)
175
+ (table.options.enableColumnPinning ??
176
+ table.options.enablePinning ??
177
+ true)
127
178
  )
128
179
  }
129
180
 
@@ -151,6 +202,69 @@ export const Pinning: TableFeature = {
151
202
  row: Row<TData>,
152
203
  table: Table<TData>
153
204
  ): void => {
205
+ row.pin = (position, includeLeafRows, includeParentRows) => {
206
+ const leafRowIds = includeLeafRows
207
+ ? row.getLeafRows().map(({ id }) => id)
208
+ : []
209
+ const parentRowIds = includeParentRows
210
+ ? row.getParentRows().map(({ id }) => id)
211
+ : []
212
+ const rowIds = new Set([...parentRowIds, row.id, ...leafRowIds])
213
+
214
+ table.setRowPinning(old => {
215
+ if (position === 'bottom') {
216
+ return {
217
+ top: (old?.top ?? []).filter(d => !rowIds?.has(d)),
218
+ bottom: [
219
+ ...(old?.bottom ?? []).filter(d => !rowIds?.has(d)),
220
+ ...Array.from(rowIds),
221
+ ],
222
+ }
223
+ }
224
+
225
+ if (position === 'top') {
226
+ return {
227
+ top: [
228
+ ...(old?.top ?? []).filter(d => !rowIds?.has(d)),
229
+ ...Array.from(rowIds),
230
+ ],
231
+ bottom: (old?.bottom ?? []).filter(d => !rowIds?.has(d)),
232
+ }
233
+ }
234
+
235
+ return {
236
+ top: (old?.top ?? []).filter(d => !rowIds?.has(d)),
237
+ bottom: (old?.bottom ?? []).filter(d => !rowIds?.has(d)),
238
+ }
239
+ })
240
+ }
241
+ row.getCanPin = () => {
242
+ const { enableRowPinning, enablePinning } = table.options
243
+ if (typeof enableRowPinning === 'function') {
244
+ return enableRowPinning(row)
245
+ }
246
+ return enableRowPinning ?? enablePinning ?? true
247
+ }
248
+ row.getIsPinned = () => {
249
+ const rowIds = [row.id]
250
+
251
+ const { top, bottom } = table.getState().rowPinning
252
+
253
+ const isTop = rowIds.some(d => top?.includes(d))
254
+ const isBottom = rowIds.some(d => bottom?.includes(d))
255
+
256
+ return isTop ? 'top' : isBottom ? 'bottom' : false
257
+ }
258
+ row.getPinnedIndex = () => {
259
+ const position = row.getIsPinned()
260
+ if (!position) return -1
261
+
262
+ const visiblePinnedRowIds = table
263
+ ._getPinnedRows(position)
264
+ ?.map(({ id }) => id)
265
+
266
+ return visiblePinnedRowIds?.indexOf(row.id) ?? -1
267
+ }
154
268
  row.getCenterVisibleCells = memo(
155
269
  () => [
156
270
  row._getAllVisibleCells(),
@@ -164,7 +278,7 @@ export const Pinning: TableFeature = {
164
278
  },
165
279
  {
166
280
  key:
167
- process.env.NODE_ENV === 'production' && 'row.getCenterVisibleCells',
281
+ process.env.NODE_ENV === 'development' && 'row.getCenterVisibleCells',
168
282
  debug: () => table.options.debugAll ?? table.options.debugRows,
169
283
  }
170
284
  )
@@ -174,12 +288,13 @@ export const Pinning: TableFeature = {
174
288
  const cells = (left ?? [])
175
289
  .map(columnId => allCells.find(cell => cell.column.id === columnId)!)
176
290
  .filter(Boolean)
177
- .map(d => ({ ...d, position: 'left' } as Cell<TData, unknown>))
291
+ .map(d => ({ ...d, position: 'left' }) as Cell<TData, unknown>)
178
292
 
179
293
  return cells
180
294
  },
181
295
  {
182
- key: process.env.NODE_ENV === 'production' && 'row.getLeftVisibleCells',
296
+ key:
297
+ process.env.NODE_ENV === 'development' && 'row.getLeftVisibleCells',
183
298
  debug: () => table.options.debugAll ?? table.options.debugRows,
184
299
  }
185
300
  )
@@ -189,13 +304,13 @@ export const Pinning: TableFeature = {
189
304
  const cells = (right ?? [])
190
305
  .map(columnId => allCells.find(cell => cell.column.id === columnId)!)
191
306
  .filter(Boolean)
192
- .map(d => ({ ...d, position: 'right' } as Cell<TData, unknown>))
307
+ .map(d => ({ ...d, position: 'right' }) as Cell<TData, unknown>)
193
308
 
194
309
  return cells
195
310
  },
196
311
  {
197
312
  key:
198
- process.env.NODE_ENV === 'production' && 'row.getRightVisibleCells',
313
+ process.env.NODE_ENV === 'development' && 'row.getRightVisibleCells',
199
314
  debug: () => table.options.debugAll ?? table.options.debugRows,
200
315
  }
201
316
  )
@@ -208,8 +323,8 @@ export const Pinning: TableFeature = {
208
323
  table.resetColumnPinning = defaultState =>
209
324
  table.setColumnPinning(
210
325
  defaultState
211
- ? getDefaultPinningState()
212
- : table.initialState?.columnPinning ?? getDefaultPinningState()
326
+ ? getDefaultColumnPinningState()
327
+ : table.initialState?.columnPinning ?? getDefaultColumnPinningState()
213
328
  )
214
329
 
215
330
  table.getIsSomeColumnsPinned = position => {
@@ -263,5 +378,72 @@ export const Pinning: TableFeature = {
263
378
  debug: () => table.options.debugAll ?? table.options.debugColumns,
264
379
  }
265
380
  )
381
+
382
+ table.setRowPinning = updater => table.options.onRowPinningChange?.(updater)
383
+
384
+ table.resetRowPinning = defaultState =>
385
+ table.setRowPinning(
386
+ defaultState
387
+ ? getDefaultRowPinningState()
388
+ : table.initialState?.rowPinning ?? getDefaultRowPinningState()
389
+ )
390
+
391
+ table.getIsSomeRowsPinned = position => {
392
+ const pinningState = table.getState().rowPinning
393
+
394
+ if (!position) {
395
+ return Boolean(pinningState.top?.length || pinningState.bottom?.length)
396
+ }
397
+ return Boolean(pinningState[position]?.length)
398
+ }
399
+
400
+ table._getPinnedRows = (position: 'top' | 'bottom') =>
401
+ memo(
402
+ () => [table.getRowModel().rows, table.getState().rowPinning[position]],
403
+ (visibleRows, pinnedRowIds) => {
404
+ const rows =
405
+ table.options.keepPinnedRows ?? true
406
+ ? //get all rows that are pinned even if they would not be otherwise visible
407
+ //account for expanded parent rows, but not pagination or filtering
408
+ (pinnedRowIds ?? []).map(rowId => {
409
+ const row = table.getRow(rowId, true)
410
+ return row.getIsAllParentsExpanded() ? row : null
411
+ })
412
+ : //else get only visible rows that are pinned
413
+ (pinnedRowIds ?? []).map(
414
+ rowId => visibleRows.find(row => row.id === rowId)!
415
+ )
416
+
417
+ return rows
418
+ .filter(Boolean)
419
+ .map(d => ({ ...d, position })) as Row<TData>[]
420
+ },
421
+ {
422
+ key:
423
+ process.env.NODE_ENV === 'development' &&
424
+ `row.get${position === 'top' ? 'Top' : 'Bottom'}Rows`,
425
+ debug: () => table.options.debugAll ?? table.options.debugRows,
426
+ }
427
+ )()
428
+
429
+ table.getTopRows = () => table._getPinnedRows('top')
430
+
431
+ table.getBottomRows = () => table._getPinnedRows('bottom')
432
+
433
+ table.getCenterRows = memo(
434
+ () => [
435
+ table.getRowModel().rows,
436
+ table.getState().rowPinning.top,
437
+ table.getState().rowPinning.bottom,
438
+ ],
439
+ (allRows, top, bottom) => {
440
+ const topAndBottom = new Set([...(top ?? []), ...(bottom ?? [])])
441
+ return allRows.filter(d => !topAndBottom.has(d.id))
442
+ },
443
+ {
444
+ key: process.env.NODE_ENV === 'development' && 'row.getCenterRows',
445
+ debug: () => table.options.debugAll ?? table.options.debugRows,
446
+ }
447
+ )
266
448
  },
267
449
  }
package/src/types.ts CHANGED
@@ -19,6 +19,10 @@ import {
19
19
  ColumnPinningOptions,
20
20
  ColumnPinningRow,
21
21
  ColumnPinningTableState,
22
+ RowPinningInstance,
23
+ RowPinningOptions,
24
+ RowPinningRow,
25
+ RowPinningTableState,
22
26
  } from './features/Pinning'
23
27
  import {
24
28
  CoreHeader,
@@ -106,6 +110,7 @@ export interface Table<TData extends RowData>
106
110
  VisibilityInstance<TData>,
107
111
  ColumnOrderInstance<TData>,
108
112
  ColumnPinningInstance<TData>,
113
+ RowPinningInstance<TData>,
109
114
  FiltersInstance<TData>,
110
115
  SortingInstance<TData>,
111
116
  GroupingInstance<TData>,
@@ -118,6 +123,7 @@ interface FeatureOptions<TData extends RowData>
118
123
  extends VisibilityOptions,
119
124
  ColumnOrderOptions,
120
125
  ColumnPinningOptions,
126
+ RowPinningOptions<TData>,
121
127
  FiltersOptions<TData>,
122
128
  SortingOptions<TData>,
123
129
  GroupingOptions,
@@ -140,6 +146,7 @@ export interface TableState
140
146
  VisibilityTableState,
141
147
  ColumnOrderTableState,
142
148
  ColumnPinningTableState,
149
+ RowPinningTableState,
143
150
  FiltersTableState,
144
151
  SortingTableState,
145
152
  ExpandedTableState,
@@ -153,6 +160,7 @@ interface CompleteInitialTableState
153
160
  VisibilityTableState,
154
161
  ColumnOrderTableState,
155
162
  ColumnPinningTableState,
163
+ RowPinningTableState,
156
164
  FiltersTableState,
157
165
  SortingTableState,
158
166
  ExpandedTableState,
@@ -167,6 +175,7 @@ export interface Row<TData extends RowData>
167
175
  extends CoreRow<TData>,
168
176
  VisibilityRow<TData>,
169
177
  ColumnPinningRow<TData>,
178
+ RowPinningRow,
170
179
  FiltersRow<TData>,
171
180
  GroupingRow,
172
181
  RowSelectionRow,