Skip to content

Commit d3e480d

Browse files
committed
add plugin system!
1 parent 1afcf94 commit d3e480d

File tree

21 files changed

+303
-179
lines changed

21 files changed

+303
-179
lines changed

examples/react/custom-features/src/main.tsx

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@ import React from 'react'
22
import ReactDOM from 'react-dom/client'
33
import './index.css'
44
import {
5+
columnFilteringFeature,
56
createFilteredRowModel,
67
createPaginatedRowModel,
78
createSortedRowModel,
9+
filterFns,
810
flexRender,
911
functionalUpdate,
1012
makeStateUpdater,
13+
rowPaginationFeature,
14+
rowSortingFeature,
15+
sortFns,
16+
tableFeatures,
1117
useTable,
1218
} from '@tanstack/react-table'
1319
import { makeData } from './makeData'
@@ -19,6 +25,7 @@ import type {
1925
Table,
2026
TableFeature,
2127
TableFeatures,
28+
TableState,
2229
Updater,
2330
} from '@tanstack/react-table'
2431
import type { Person } from './makeData'
@@ -27,40 +34,42 @@ import type { Person } from './makeData'
2734

2835
// define types for our new feature's custom state
2936
export type DensityState = 'sm' | 'md' | 'lg'
30-
export interface DensityTableState {
37+
export interface TableState_Density {
3138
density: DensityState
3239
}
3340

3441
// define types for our new feature's table options
35-
export interface DensityOptions {
42+
export interface TableOptions_Density {
3643
enableDensity?: boolean
3744
onDensityChange?: OnChangeFn<DensityState>
3845
}
3946

4047
// Define types for our new feature's table APIs
41-
export interface DensityInstance {
48+
export interface Table_Density {
4249
setDensity: (updater: Updater<DensityState>) => void
4350
toggleDensity: (value?: DensityState) => void
4451
}
4552

4653
// Use declaration merging to add our new feature APIs and state types to TanStack Table's existing types.
4754
declare module '@tanstack/react-table' {
55+
// declare our new feature as a plugin
56+
interface Plugins {
57+
densityPlugin: TableFeature
58+
}
4859
// merge our new feature's state with the existing table state
49-
interface TableState extends DensityTableState {}
60+
interface TableState_Plugins extends TableState_Density {}
5061
// merge our new feature's options with the existing table options
51-
interface TableOptions<TFeatures extends TableFeatures, TData extends RowData>
52-
extends DensityOptions {}
62+
interface TableOptions_Plugins extends TableOptions_Density {}
5363
// merge our new feature's instance APIs with the existing table instance APIs
54-
interface Table<TFeatures extends TableFeatures, TData extends RowData>
55-
extends DensityInstance {}
64+
interface Table_Plugins extends Table_Density {}
5665
// if you need to add cell instance APIs...
57-
// interface Cell<TFeatures extends TableFeatures, TData extends RowData, TValue> extends DensityCell
66+
// interface Cell_Plugins extends Cell_Density {}
5867
// if you need to add row instance APIs...
59-
// interface Row<TFeatures extends TableFeatures, TData extends RowData> extends DensityRow
68+
// interface Row_Plugins extends Row_Density {}
6069
// if you need to add column instance APIs...
61-
// interface Column<TFeatures extends TableFeatures, TData extends RowData, TValue> extends DensityColumn
70+
// interface Column_Plugins extends Column_Density {}
6271
// if you need to add header instance APIs...
63-
// interface Header<TFeatures extends TableFeatures, TData extends RowData, TValue> extends DensityHeader
72+
// interface Header_Plugins extends Header_Density {}
6473

6574
// Note: declaration merging on `ColumnDef` is not possible because it is a type, not an interface.
6675
// But you can still use declaration merging on `ColumnDef.meta`
@@ -69,12 +78,14 @@ declare module '@tanstack/react-table' {
6978
// end of TS setup!
7079

7180
// Here is all of the actual javascript code for our new feature
72-
export const DensityFeature: TableFeature = {
81+
export const densityPlugin: TableFeature = {
7382
// define the new feature's initial state
74-
getInitialState: (state): DensityTableState => {
83+
getInitialState: <TFeatures extends TableFeatures>(
84+
initialState: Partial<TableState<TFeatures>>,
85+
): Partial<TableState<TFeatures>> => {
7586
return {
7687
density: 'md',
77-
...state,
88+
...initialState, // must come last
7889
}
7990
},
8091

@@ -83,20 +94,20 @@ export const DensityFeature: TableFeature = {
8394
TFeatures extends TableFeatures,
8495
TData extends RowData,
8596
>(
86-
table: Partial<Table<TFeatures, TData>>,
87-
): DensityOptions => {
97+
table: Table<TFeatures, TData>,
98+
): TableOptions_Density => {
8899
return {
89100
enableDensity: true,
90101
onDensityChange: makeStateUpdater('density', table),
91-
} as DensityOptions
102+
} as TableOptions_Density
92103
},
93104
// if you need to add a default column definition...
94105
// getDefaultColumnDef: <TFeatures extends TableFeatures, TData extends RowData>(): Partial<ColumnDef<TFeatures, TData>> => {
95106
// return { meta: {} } //use meta instead of directly adding to the columnDef to avoid typescript stuff that's hard to workaround
96107
// },
97108

98109
// define the new feature's table instance methods
99-
constructTable: <TFeatures extends TableFeatures, TData extends RowData>(
110+
constructTableAPIs: <TFeatures extends TableFeatures, TData extends RowData>(
100111
table: Table<TFeatures, TData>,
101112
): void => {
102113
table.setDensity = (updater) => {
@@ -114,20 +125,27 @@ export const DensityFeature: TableFeature = {
114125
}
115126
},
116127

117-
// if you need to add row instance APIs...
118-
// constructRow: <TFeatures extends TableFeatures, TData extends RowData>(row, table): void => {},
119-
// if you need to add cell instance APIs...
120-
// constructCell: <TFeatures extends TableFeatures, TData extends RowData>(cell, column, row, table): void => {},
121-
// if you need to add column instance APIs...
122-
// constructColumn: <TFeatures extends TableFeatures, TData extends RowData>(column, table): void => {},
123-
// if you need to add header instance APIs...
124-
// constructHeader: <TFeatures extends TableFeatures, TData extends RowData>(header, table): void => {},
128+
// // if you need to add row instance APIs...
129+
// constructRowAPIs: <TFeatures extends TableFeatures, TData extends RowData>(row: Row<TFeatures, TData>, table: Table<TFeatures, TData>): void => {},
130+
// // if you need to add cell instance APIs...
131+
// constructCellAPIs: <TFeatures extends TableFeatures, TData extends RowData, TValue extends CellData = CellData>(cell: Cell<TFeatures, TData, TValue>): void => {},
132+
// // if you need to add column instance APIs...
133+
// constructColumnAPIs: <TFeatures extends TableFeatures, TData extends RowData, TValue extends CellData = CellData>(column: Column<TFeatures, TData, TValue>): void => {},
134+
// // if you need to add header instance APIs...
135+
// constructHeaderAPIs: <TFeatures extends TableFeatures, TData extends RowData, TValue extends CellData = CellData>(header: Header<TFeatures, TData, TValue>): void => {},
125136
}
126137
// end of custom feature code
127138

128139
// app code
140+
const _features = tableFeatures({
141+
columnFilteringFeature,
142+
rowSortingFeature,
143+
rowPaginationFeature,
144+
densityPlugin, // pass in our plugin just like any other stock feature
145+
})
146+
129147
function App() {
130-
const columns = React.useMemo<Array<ColumnDef<any, Person>>>(
148+
const columns = React.useMemo<Array<ColumnDef<typeof _features, Person>>>(
131149
() => [
132150
{
133151
accessorKey: 'firstName',
@@ -169,12 +187,16 @@ function App() {
169187
const [density, setDensity] = React.useState<DensityState>('md')
170188

171189
const table = useTable({
172-
_features: { DensityFeature }, // pass our custom feature to the table to be instantiated upon creation
190+
_features,
173191
_rowModels: {
174192
filteredRowModel: createFilteredRowModel(),
175193
paginatedRowModel: createPaginatedRowModel(),
176194
sortedRowModel: createSortedRowModel(),
177195
},
196+
_processingFns: {
197+
filterFns,
198+
sortFns,
199+
},
178200
columns,
179201
data,
180202
debugTable: true,
@@ -245,7 +267,7 @@ function App() {
245267
{table.getRowModel().rows.map((row) => {
246268
return (
247269
<tr key={row.id}>
248-
{row.getVisibleCells().map((cell) => {
270+
{row.getAllCells().map((cell) => {
249271
return (
250272
<td
251273
key={cell.id}
@@ -347,17 +369,15 @@ function Filter({
347369
column,
348370
table,
349371
}: {
350-
column: Column<any, any>
351-
table: Table<any, any>
372+
column: Column<typeof _features, Person>
373+
table: Table<typeof _features, Person>
352374
}) {
353375
const firstValue = table
354376
.getPreFilteredRowModel()
355377
.flatRows[0]?.getValue(column.id)
356378

357379
const columnFilterValue = column.getFilterValue()
358380

359-
console.log('columnFilterValue', { columnFilterValue, table, column })
360-
361381
return typeof firstValue === 'number' ? (
362382
<div className="flex space-x-2">
363383
<input

packages/table-core/src/features/column-faceting/createFacetedMinMaxValues.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ import { column_getFacetedRowModel } from './columnFacetingFeature.utils'
33
import type { RowModel } from '../../core/row-models/rowModelsFeature.types'
44
import type { Table_Internal } from '../../types/Table'
55
import type { TableFeatures } from '../../types/TableFeatures'
6+
import type { RowData } from '../../types/type-utils'
67

7-
export function createFacetedMinMaxValues<TFeatures extends TableFeatures>(): (
8-
table: Table_Internal<TFeatures, any>,
8+
export function createFacetedMinMaxValues<
9+
TFeatures extends TableFeatures,
10+
TData extends RowData = any,
11+
>(): (
12+
table: Table_Internal<TFeatures, TData>,
913
columnId: string,
1014
) => () => undefined | [number, number] {
1115
return (table, columnId) =>
@@ -20,9 +24,12 @@ export function createFacetedMinMaxValues<TFeatures extends TableFeatures>(): (
2024
})
2125
}
2226

23-
function _createFacetedMinMaxValues<TFeatures extends TableFeatures>(
27+
function _createFacetedMinMaxValues<
28+
TFeatures extends TableFeatures,
29+
TData extends RowData = any,
30+
>(
2431
columnId: string,
25-
facetedRowModel?: RowModel<TFeatures, any>,
32+
facetedRowModel?: RowModel<TFeatures, TData>,
2633
): undefined | [number, number] {
2734
if (!facetedRowModel) return undefined
2835

packages/table-core/src/features/column-faceting/createFacetedRowModel.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@ import type {
88
import type { TableFeatures } from '../../types/TableFeatures'
99
import type { RowModel } from '../../core/row-models/rowModelsFeature.types'
1010
import type { Row } from '../../types/Row'
11+
import type { RowData } from '../../types/type-utils'
1112

12-
export function createFacetedRowModel<TFeatures extends TableFeatures>(): (
13-
table: Table_Internal<TFeatures, any>,
13+
export function createFacetedRowModel<
14+
TFeatures extends TableFeatures,
15+
TData extends RowData = any,
16+
>(): (
17+
table: Table_Internal<TFeatures, TData>,
1418
columnId: string,
15-
) => () => RowModel<TFeatures, any> {
19+
) => () => RowModel<TFeatures, TData> {
1620
return (table, columnId) =>
1721
tableMemo({
1822
debug: isDev && (table.options.debugAll ?? table.options.debugTable),
@@ -34,10 +38,13 @@ export function createFacetedRowModel<TFeatures extends TableFeatures>(): (
3438
})
3539
}
3640

37-
function _createFacetedRowModel<TFeatures extends TableFeatures>(
38-
table: Table_Internal<TFeatures, any>,
41+
function _createFacetedRowModel<
42+
TFeatures extends TableFeatures,
43+
TData extends RowData = any,
44+
>(
45+
table: Table_Internal<TFeatures, TData>,
3946
columnId: string,
40-
preRowModel: RowModel<TFeatures, any>,
47+
preRowModel: RowModel<TFeatures, TData>,
4148
columnFilters?: ColumnFiltersState,
4249
globalFilter?: string,
4350
) {
@@ -51,7 +58,7 @@ function _createFacetedRowModel<TFeatures extends TableFeatures>(
5158
].filter(Boolean) as Array<string>
5259

5360
const filterRowsImpl = (
54-
row: Row<TFeatures, any> & Partial<Row_ColumnFiltering<TFeatures, any>>,
61+
row: Row<TFeatures, TData> & Partial<Row_ColumnFiltering<TFeatures, TData>>,
5562
) => {
5663
// Horizontally filter rows through each column
5764
for (const colId of filterableIds) {

packages/table-core/src/features/column-faceting/createFacetedUniqueValues.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ import { column_getFacetedRowModel } from './columnFacetingFeature.utils'
33
import type { Table_Internal } from '../../types/Table'
44
import type { RowModel } from '../../core/row-models/rowModelsFeature.types'
55
import type { TableFeatures } from '../../types/TableFeatures'
6+
import type { RowData } from '../../types/type-utils'
67

7-
export function createFacetedUniqueValues<TFeatures extends TableFeatures>(): (
8-
table: Table_Internal<TFeatures, any>,
8+
export function createFacetedUniqueValues<
9+
TFeatures extends TableFeatures,
10+
TData extends RowData = any,
11+
>(): (
12+
table: Table_Internal<TFeatures, TData>,
913
columnId: string,
1014
) => () => Map<any, number> {
1115
return (table, columnId) =>
@@ -20,9 +24,12 @@ export function createFacetedUniqueValues<TFeatures extends TableFeatures>(): (
2024
})
2125
}
2226

23-
function _createFacetedUniqueValues<TFeatures extends TableFeatures>(
27+
function _createFacetedUniqueValues<
28+
TFeatures extends TableFeatures,
29+
TData extends RowData = any,
30+
>(
2431
columnId: string,
25-
facetedRowModel: RowModel<TFeatures, any> | undefined,
32+
facetedRowModel: RowModel<TFeatures, TData> | undefined,
2633
): Map<any, number> {
2734
if (!facetedRowModel) return new Map()
2835

packages/table-core/src/features/column-filtering/createFilteredRowModel.ts

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
import { table_autoResetPageIndex } from '../row-pagination/rowPaginationFeature.utils'
88
import { filterRows } from './filterRowsUtils'
99
import { column_getFilterFn } from './columnFilteringFeature.utils'
10+
import type { RowData } from '../../types/type-utils'
1011
import type { TableFeatures } from '../../types/TableFeatures'
1112
import type { RowModel } from '../../core/row-models/rowModelsFeature.types'
1213
import type { Table_Internal } from '../../types/Table'
@@ -16,9 +17,12 @@ import type {
1617
Row_ColumnFiltering,
1718
} from './columnFilteringFeature.types'
1819

19-
export function createFilteredRowModel<TFeatures extends TableFeatures>(): (
20-
table: Table_Internal<TFeatures, any>,
21-
) => () => RowModel<TFeatures, any> {
20+
export function createFilteredRowModel<
21+
TFeatures extends TableFeatures,
22+
TData extends RowData = any,
23+
>(): (
24+
table: Table_Internal<TFeatures, TData>,
25+
) => () => RowModel<TFeatures, TData> {
2226
return (table) =>
2327
tableMemo({
2428
debug: isDev && (table.options.debugAll ?? table.options.debugTable),
@@ -33,24 +37,27 @@ export function createFilteredRowModel<TFeatures extends TableFeatures>(): (
3337
})
3438
}
3539

36-
function _createFilteredRowModel<TFeatures extends TableFeatures>(
37-
table: Table_Internal<TFeatures, any>,
38-
): RowModel<TFeatures, any> {
40+
function _createFilteredRowModel<
41+
TFeatures extends TableFeatures,
42+
TData extends RowData = any,
43+
>(table: Table_Internal<TFeatures, TData>): RowModel<TFeatures, TData> {
3944
const rowModel = table.getPreFilteredRowModel()
4045
const { columnFilters, globalFilter } = table.options.state ?? {}
4146

4247
if (!rowModel.rows.length || (!columnFilters?.length && !globalFilter)) {
4348
for (const row of rowModel.flatRows as Array<
44-
Row<TFeatures, any> & Partial<Row_ColumnFiltering<TFeatures, any>>
49+
Row<TFeatures, TData> & Partial<Row_ColumnFiltering<TFeatures, TData>>
4550
>) {
4651
row.columnFilters = {}
4752
row.columnFiltersMeta = {}
4853
}
4954
return rowModel
5055
}
5156

52-
const resolvedColumnFilters: Array<ResolvedColumnFilter<TFeatures, any>> = []
53-
const resolvedGlobalFilters: Array<ResolvedColumnFilter<TFeatures, any>> = []
57+
const resolvedColumnFilters: Array<ResolvedColumnFilter<TFeatures, TData>> =
58+
[]
59+
const resolvedGlobalFilters: Array<ResolvedColumnFilter<TFeatures, TData>> =
60+
[]
5461

5562
columnFilters?.forEach((columnFilter) => {
5663
const column = table_getColumn(table, columnFilter.id)
@@ -92,7 +99,7 @@ function _createFilteredRowModel<TFeatures extends TableFeatures>(
9299

93100
// Flag the pre-filtered row model with each filter state
94101
for (const row of rowModel.flatRows as Array<
95-
Row<TFeatures, any> & Partial<Row_ColumnFiltering<TFeatures, any>>
102+
Row<TFeatures, TData> & Partial<Row_ColumnFiltering<TFeatures, TData>>
96103
>) {
97104
row.columnFilters = {}
98105

@@ -142,7 +149,7 @@ function _createFilteredRowModel<TFeatures extends TableFeatures>(
142149
}
143150

144151
const filterRowsImpl = (
145-
row: Row<TFeatures, any> & Row_ColumnFiltering<TFeatures, any>,
152+
row: Row<TFeatures, TData> & Row_ColumnFiltering<TFeatures, TData>,
146153
) => {
147154
// Horizontally filter rows through each column
148155
for (const columnId of filterableIds) {

0 commit comments

Comments
 (0)