@tanstack/table-core 8.2.6 → 8.3.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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tanstack/table-core",
3
3
  "author": "Tanner Linsley",
4
- "version": "8.2.6",
4
+ "version": "8.3.2",
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",
@@ -0,0 +1,74 @@
1
+ import { AccessorFn, ColumnDef, RowData } from './types'
2
+ import { DeepKeys, DeepValue } from './utils'
3
+
4
+ // type Person = {
5
+ // firstName: string
6
+ // lastName: string
7
+ // age: number
8
+ // visits: number
9
+ // status: string
10
+ // progress: number
11
+ // nested: {
12
+ // foo: [
13
+ // {
14
+ // bar: 'bar'
15
+ // }
16
+ // ]
17
+ // bar: { subBar: boolean }[]
18
+ // baz: {
19
+ // foo: 'foo'
20
+ // bar: {
21
+ // baz: 'baz'
22
+ // }
23
+ // }
24
+ // }
25
+ // }
26
+
27
+ // const test: DeepKeys<Person> = 'nested.foo.0.bar'
28
+ // const test2: DeepKeys<Person> = 'nested.bar'
29
+
30
+ // const helper = createColumnHelper<Person>()
31
+
32
+ // helper.accessor('nested.foo', {
33
+ // cell: info => info.getValue(),
34
+ // })
35
+
36
+ // helper.accessor('nested.foo.0.bar', {
37
+ // cell: info => info.getValue(),
38
+ // })
39
+
40
+ // helper.accessor('nested.bar', {
41
+ // cell: info => info.getValue(),
42
+ // })
43
+
44
+ export type ColumnHelper<TData extends RowData> = {
45
+ accessor: <
46
+ TAccessor extends AccessorFn<TData> | DeepKeys<TData>,
47
+ TValue extends TAccessor extends AccessorFn<TData, infer TReturn>
48
+ ? TReturn
49
+ : TAccessor extends DeepKeys<TData>
50
+ ? DeepValue<TData, TAccessor>
51
+ : never
52
+ >(
53
+ accessor: TAccessor,
54
+ column: Omit<ColumnDef<TData, TValue>, 'accessorKey'>
55
+ ) => ColumnDef<TData, TValue>
56
+ }
57
+
58
+ export function createColumnHelper<
59
+ TData extends RowData
60
+ >(): ColumnHelper<TData> {
61
+ return {
62
+ accessor: (accessor, column) => {
63
+ return typeof accessor === 'function'
64
+ ? ({
65
+ ...column,
66
+ accessorFn: accessor,
67
+ } as any)
68
+ : {
69
+ ...column,
70
+ accessorKey: accessor,
71
+ }
72
+ },
73
+ }
74
+ }
package/src/core/cell.ts CHANGED
@@ -1,19 +1,26 @@
1
1
  import { RowData, Cell, Column, Row, Table } from '../types'
2
+ import { IsAny, IsKnown } from '../utils'
3
+
4
+ type NoInfer<T> = [T][T extends any ? 0 : never]
5
+
6
+ type Getter<TValue> = <TTValue = TValue>() => NoInfer<TTValue>
7
+
8
+ export type CellContext<TData extends RowData, TValue> = {
9
+ table: Table<TData>
10
+ column: Column<TData, TValue>
11
+ row: Row<TData>
12
+ cell: Cell<TData, TValue>
13
+ getValue: Getter<TValue>
14
+ renderValue: Getter<TValue | null>
15
+ }
2
16
 
3
17
  export type CoreCell<TData extends RowData, TValue> = {
4
18
  id: string
5
- getValue: <TTValue = TValue>() => TTValue
6
- renderValue: <TTValue = TValue>() => TTValue | null
19
+ getValue: CellContext<TData, TValue>['getValue']
20
+ renderValue: CellContext<TData, TValue>['renderValue']
7
21
  row: Row<TData>
8
22
  column: Column<TData, TValue>
9
- getContext: () => {
10
- table: Table<TData>
11
- column: Column<TData, TValue>
12
- row: Row<TData>
13
- cell: Cell<TData, TValue>
14
- getValue: <TTValue = TValue>() => TTValue
15
- renderValue: <TTValue = TValue>() => TTValue | null
16
- }
23
+ getContext: () => CellContext<TData, TValue>
17
24
  }
18
25
 
19
26
  export function createCell<TData extends RowData, TValue>(
@@ -7,32 +7,26 @@ import {
7
7
  RowData,
8
8
  ColumnMeta,
9
9
  } from '../types'
10
- import { memo, UnionToIntersection } from '../utils'
11
- import { CoreCell } from './cell'
12
- import { CoreHeader } from './headers'
13
-
14
- export type CoreColumnDefType = 'data' | 'display' | 'group'
15
-
16
- type CoreColumnDefBase<TData extends RowData, TValue> = {
17
- columns?: ColumnDef<TData>[]
18
- header?: ColumnDefTemplate<
19
- ReturnType<CoreHeader<TData, TValue>['getContext']>
20
- >
21
- footer?: ColumnDefTemplate<
22
- ReturnType<CoreHeader<TData, TValue>['getContext']>
23
- >
24
- cell?: ColumnDefTemplate<ReturnType<CoreCell<TData, TValue>['getContext']>>
25
- meta?: ColumnMeta
10
+ import { DeepKeys, IsKnown, memo, UnionToIntersection } from '../utils'
11
+ import { CellContext } from './cell'
12
+ import { HeaderContext } from './headers'
13
+
14
+ export type CoreColumnDefBase<TData extends RowData, TValue> = {
15
+ columns?: ColumnDef<TData, unknown>[]
16
+ header?: ColumnDefTemplate<HeaderContext<TData, TValue>>
17
+ footer?: ColumnDefTemplate<HeaderContext<TData, TValue>>
18
+ cell?: ColumnDefTemplate<CellContext<TData, TValue>>
19
+ meta?: ColumnMeta<TData, TValue>
26
20
  }
27
21
 
28
- type CoreColumnDefDisplay<TData extends RowData, TValue> = CoreColumnDefBase<
29
- TData,
22
+ export type CoreColumnDefDisplay<
23
+ TData extends RowData,
30
24
  TValue
31
- > & {
25
+ > = CoreColumnDefBase<TData, TValue> & {
32
26
  id: string
33
27
  }
34
28
 
35
- type CoreColumnDefDisplayWithStringHeader<
29
+ export type CoreColumnDefDisplayWithStringHeader<
36
30
  TData extends RowData,
37
31
  TValue
38
32
  > = CoreColumnDefBase<TData, TValue> & {
@@ -40,40 +34,40 @@ type CoreColumnDefDisplayWithStringHeader<
40
34
  id?: string
41
35
  }
42
36
 
43
- type CoreColumnDefAccessorFn<
37
+ export type CoreColumnDefAccessorFn<
44
38
  TData extends RowData,
45
- TValue = unknown
39
+ TValue
46
40
  > = CoreColumnDefBase<TData, TValue> & {
47
41
  accessorFn: AccessorFn<TData, TValue>
48
42
  id: string
49
- // accessorKey?: never
50
43
  }
51
44
 
52
- type CoreColumnDefAccessorKey<
45
+ export type CoreColumnDefAccessorKey<
53
46
  TData extends RowData,
54
47
  TValue
55
48
  > = CoreColumnDefBase<TData, TValue> & {
56
- accessorKey: keyof TData
49
+ accessorKey: DeepKeys<TData>
57
50
  id?: string
58
- // accessorFn?: never
59
51
  }
60
52
 
61
53
  export type CoreColumnDef<TData extends RowData, TValue> =
62
54
  | CoreColumnDefDisplay<TData, TValue>
63
55
  | CoreColumnDefDisplayWithStringHeader<TData, TValue>
64
- | CoreColumnDefAccessorFn<TData>
56
+ | CoreColumnDefAccessorFn<TData, TValue>
65
57
  | CoreColumnDefAccessorKey<TData, TValue>
66
58
 
67
59
  export type CoreColumnDefResolved<
68
60
  TData extends RowData,
69
61
  TValue = unknown
70
- > = Partial<UnionToIntersection<CoreColumnDef<TData, TValue>>>
62
+ > = Partial<UnionToIntersection<CoreColumnDef<TData, TValue>>> & {
63
+ accessorKey?: string
64
+ }
71
65
 
72
66
  export type CoreColumn<TData extends RowData, TValue> = {
73
67
  id: string
74
68
  depth: number
75
69
  accessorFn?: AccessorFn<TData, TValue>
76
- columnDef: ColumnDef<TData>
70
+ columnDef: ColumnDef<TData, TValue>
77
71
  columns: Column<TData, TValue>[]
78
72
  parent?: Column<TData, TValue>
79
73
  getFlatColumns: () => Column<TData, TValue>[]
@@ -82,7 +76,7 @@ export type CoreColumn<TData extends RowData, TValue> = {
82
76
 
83
77
  export function createColumn<TData extends RowData, TValue>(
84
78
  table: Table<TData>,
85
- columnDef: ColumnDef<TData>,
79
+ columnDef: ColumnDef<TData, TValue>,
86
80
  depth: number,
87
81
  parent?: Column<TData, TValue>
88
82
  ) {
@@ -93,9 +87,11 @@ export function createColumn<TData extends RowData, TValue>(
93
87
  ...columnDef,
94
88
  } as CoreColumnDefResolved<TData>
95
89
 
90
+ const accessorKey = resolvedColumnDef.accessorKey
91
+
96
92
  let id =
97
93
  resolvedColumnDef.id ??
98
- resolvedColumnDef.accessorKey ??
94
+ (accessorKey ? accessorKey.replace('.', '_') : undefined) ??
99
95
  (typeof resolvedColumnDef.header === 'string'
100
96
  ? resolvedColumnDef.header
101
97
  : undefined)
@@ -104,9 +100,22 @@ export function createColumn<TData extends RowData, TValue>(
104
100
 
105
101
  if (resolvedColumnDef.accessorFn) {
106
102
  accessorFn = resolvedColumnDef.accessorFn
107
- } else if (resolvedColumnDef.accessorKey) {
108
- accessorFn = (originalRow: TData) =>
109
- (originalRow as any)[resolvedColumnDef.accessorKey]
103
+ } else if (accessorKey) {
104
+ // Support deep accessor keys
105
+ if (accessorKey.includes('.')) {
106
+ accessorFn = (originalRow: TData) => {
107
+ let result = originalRow as Record<string, any>
108
+
109
+ for (const key of accessorKey.split('.')) {
110
+ result = result[key]
111
+ }
112
+
113
+ return result
114
+ }
115
+ } else {
116
+ accessorFn = (originalRow: TData) =>
117
+ (originalRow as any)[resolvedColumnDef.accessorKey]
118
+ }
110
119
  }
111
120
 
112
121
  if (!id) {
@@ -125,7 +134,7 @@ export function createColumn<TData extends RowData, TValue>(
125
134
  accessorFn,
126
135
  parent: parent as any,
127
136
  depth,
128
- columnDef: resolvedColumnDef as ColumnDef<TData>,
137
+ columnDef: resolvedColumnDef as ColumnDef<TData, any>,
129
138
  columns: [],
130
139
  getFlatColumns: memo(
131
140
  () => [true],
@@ -8,6 +8,12 @@ export type CoreHeaderGroup<TData extends RowData> = {
8
8
  headers: Header<TData, unknown>[]
9
9
  }
10
10
 
11
+ export type HeaderContext<TData, TValue> = {
12
+ table: Table<TData>
13
+ header: Header<TData, TValue>
14
+ column: Column<TData, TValue>
15
+ }
16
+
11
17
  export type CoreHeader<TData extends RowData, TValue> = {
12
18
  id: string
13
19
  index: number
@@ -20,11 +26,7 @@ export type CoreHeader<TData extends RowData, TValue> = {
20
26
  getLeafHeaders: () => Header<TData, unknown>[]
21
27
  isPlaceholder: boolean
22
28
  placeholderId?: string
23
- getContext: () => {
24
- table: Table<TData>
25
- header: Header<TData, TValue>
26
- column: Column<TData, TValue>
27
- }
29
+ getContext: () => HeaderContext<TData, TValue>
28
30
  }
29
31
 
30
32
  export type HeadersInstance<TData extends RowData> = {
@@ -78,7 +80,7 @@ function createHeader<TData extends RowData, TValue>(
78
80
  getLeafHeaders: (): Header<TData, unknown>[] => {
79
81
  const leafHeaders: Header<TData, unknown>[] = []
80
82
 
81
- const recurseHeader = (h: CoreHeader<TData, unknown>) => {
83
+ const recurseHeader = (h: CoreHeader<TData, any>) => {
82
84
  if (h.subHeaders && h.subHeaders.length) {
83
85
  h.subHeaders.map(recurseHeader)
84
86
  }
package/src/core/table.ts CHANGED
@@ -80,8 +80,8 @@ export type CoreOptions<TData extends RowData> = {
80
80
  getCoreRowModel: (table: Table<any>) => () => RowModel<any>
81
81
  getSubRows?: (originalRow: TData, index: number) => undefined | TData[]
82
82
  getRowId?: (originalRow: TData, index: number, parent?: Row<TData>) => string
83
- columns: ColumnDef<TData>[]
84
- defaultColumn?: Partial<ColumnDef<TData>>
83
+ columns: ColumnDef<TData, any>[]
84
+ defaultColumn?: Partial<ColumnDef<TData, unknown>>
85
85
  renderFallbackValue: any
86
86
  }
87
87
 
@@ -99,8 +99,8 @@ export type CoreInstance<TData extends RowData> = {
99
99
  _getCoreRowModel?: () => RowModel<TData>
100
100
  getRowModel: () => RowModel<TData>
101
101
  getRow: (id: string) => Row<TData>
102
- _getDefaultColumnDef: () => Partial<ColumnDef<TData>>
103
- _getColumnDefs: () => ColumnDef<TData>[]
102
+ _getDefaultColumnDef: () => Partial<ColumnDef<TData, unknown>>
103
+ _getColumnDefs: () => ColumnDef<TData, unknown>[]
104
104
  _getAllFlatColumnsById: () => Record<string, Column<TData, unknown>>
105
105
  getAllColumns: () => Column<TData, unknown>[]
106
106
  getAllFlatColumns: () => Column<TData, unknown>[]
@@ -227,7 +227,9 @@ export function createTable<TData extends RowData>(
227
227
  _getDefaultColumnDef: memo(
228
228
  () => [table.options.defaultColumn],
229
229
  defaultColumn => {
230
- defaultColumn = (defaultColumn ?? {}) as Partial<ColumnDef<TData>>
230
+ defaultColumn = (defaultColumn ?? {}) as Partial<
231
+ ColumnDef<TData, unknown>
232
+ >
231
233
 
232
234
  return {
233
235
  header: props => props.header.column.id,
@@ -237,7 +239,7 @@ export function createTable<TData extends RowData>(
237
239
  return Object.assign(obj, feature.getDefaultColumnDef?.())
238
240
  }, {}),
239
241
  ...defaultColumn,
240
- } as Partial<ColumnDef<TData>>
242
+ } as Partial<ColumnDef<TData, unknown>>
241
243
  },
242
244
  {
243
245
  debug: () => table.options.debugAll ?? table.options.debugColumns,
@@ -251,7 +253,7 @@ export function createTable<TData extends RowData>(
251
253
  () => [table._getColumnDefs()],
252
254
  columnDefs => {
253
255
  const recurseColumns = (
254
- columnDefs: ColumnDef<TData>[],
256
+ columnDefs: ColumnDef<TData, unknown>[],
255
257
  parent?: Column<TData, unknown>,
256
258
  depth = 0
257
259
  ): Column<TData, unknown>[] => {
@@ -283,7 +283,7 @@ export const RowSelection: TableFeature = {
283
283
  )
284
284
 
285
285
  if (isAllRowsSelected) {
286
- if (preFilteredFlatRows.some(row => !rowSelection[row.id])) {
286
+ if (preFilteredFlatRows.some(row => row.getCanSelect() && !rowSelection[row.id])) {
287
287
  isAllRowsSelected = false
288
288
  }
289
289
  }
@@ -308,10 +308,8 @@ export const RowSelection: TableFeature = {
308
308
  },
309
309
 
310
310
  getIsSomeRowsSelected: () => {
311
- return (
312
- !table.getIsAllRowsSelected() &&
313
- !!Object.keys(table.getState().rowSelection ?? {}).length
314
- )
311
+ const totalSelected = Object.keys(table.getState().rowSelection ?? {}).length
312
+ return totalSelected < table.getCoreRowModel().flatRows.length
315
313
  },
316
314
 
317
315
  getIsSomePageRowsSelected: () => {
@@ -319,8 +317,8 @@ export const RowSelection: TableFeature = {
319
317
  return table.getIsAllPageRowsSelected()
320
318
  ? false
321
319
  : paginationFlatRows.some(
322
- d => d.getIsSelected() || d.getIsSomeSelected()
323
- )
320
+ d => d.getIsSelected() || d.getIsSomeSelected()
321
+ )
324
322
  },
325
323
 
326
324
  getToggleAllRowsSelectedHandler: () => {
package/src/index.ts CHANGED
@@ -16,6 +16,7 @@ export * from './features/Visibility'
16
16
  export * from './filterFns'
17
17
  export * from './sortingFns'
18
18
  export * from './aggregationFns'
19
+ export * from './columnHelper'
19
20
  export * from './utils'
20
21
  export * from './utils/getCoreRowModel'
21
22
  export * from './utils/getFilteredRowModel'
package/src/types.ts CHANGED
@@ -78,7 +78,7 @@ import { PartialKeys } from './utils'
78
78
  import { CoreCell } from './core/cell'
79
79
 
80
80
  export interface TableMeta {}
81
- export interface ColumnMeta {}
81
+ export interface ColumnMeta<TData extends RowData, TValue> {}
82
82
  export interface FilterMeta {}
83
83
 
84
84
  export type Updater<T> = T | ((old: T) => T)
package/src/utils.ts CHANGED
@@ -15,7 +15,57 @@ export type UnionToIntersection<T> = (
15
15
  ? R
16
16
  : never
17
17
 
18
- export type IfDefined<T, N> = 0 extends 1 & T ? N : T extends {} ? T : N
18
+ export type IsAny<T, Y, N> = 1 extends 0 & T ? Y : N
19
+ export type IsKnown<T, Y, N> = unknown extends T ? N : Y
20
+
21
+ type ComputeRange<
22
+ N extends number,
23
+ Result extends Array<unknown> = []
24
+ > = Result['length'] extends N
25
+ ? Result
26
+ : ComputeRange<N, [...Result, Result['length']]>
27
+ type Index100 = ComputeRange<100>[number]
28
+
29
+ // Is this type a tuple?
30
+ type IsTuple<T> = T extends readonly any[] & { length: infer Length }
31
+ ? Length extends Index100
32
+ ? T
33
+ : never
34
+ : never
35
+
36
+ // If this type is a tuple, what indices are allowed?
37
+ type AllowedIndexes<
38
+ Tuple extends ReadonlyArray<any>,
39
+ Keys extends number = never
40
+ > = Tuple extends readonly []
41
+ ? Keys
42
+ : Tuple extends readonly [infer _, ...infer Tail]
43
+ ? AllowedIndexes<Tail, Keys | Tail['length']>
44
+ : Keys
45
+
46
+ export type DeepKeys<T> = unknown extends T
47
+ ? keyof T
48
+ : object extends T
49
+ ? string
50
+ : T extends readonly any[] & IsTuple<T>
51
+ ? AllowedIndexes<T> | DeepKeysPrefix<T, AllowedIndexes<T>>
52
+ : T extends any[]
53
+ ? never & 'Dynamic length array indexing is not supported'
54
+ : T extends object
55
+ ? (keyof T & string) | DeepKeysPrefix<T, keyof T>
56
+ : never
57
+
58
+ type DeepKeysPrefix<T, TPrefix> = TPrefix extends keyof T & (number | string)
59
+ ? `${TPrefix}.${DeepKeys<T[TPrefix]> & string}`
60
+ : never
61
+
62
+ export type DeepValue<T, TProp> = T extends Record<string | number, any>
63
+ ? TProp extends `${infer TBranch}.${infer TDeepProp}`
64
+ ? DeepValue<T[TBranch], TDeepProp>
65
+ : T[TProp & string]
66
+ : never
67
+
68
+ ///
19
69
 
20
70
  export function functionalUpdate<T>(updater: Updater<T>, input: T): T {
21
71
  return typeof updater === 'function'