@tanstack/table-core 9.0.0-beta.46 → 9.0.0-beta.48
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/coreRowModelsFeature.types.d.cts +1 -1
- package/dist/core/row-models/coreRowModelsFeature.types.d.ts +1 -1
- package/dist/core/row-models/coreRowModelsFeature.utils.cjs +1 -1
- package/dist/core/row-models/coreRowModelsFeature.utils.cjs.map +1 -1
- package/dist/core/row-models/coreRowModelsFeature.utils.d.cts +1 -1
- package/dist/core/row-models/coreRowModelsFeature.utils.d.ts +1 -1
- package/dist/core/row-models/coreRowModelsFeature.utils.js +1 -1
- package/dist/core/row-models/coreRowModelsFeature.utils.js.map +1 -1
- package/dist/features/aggregation/aggregationFeature.cjs +38 -0
- package/dist/features/aggregation/aggregationFeature.cjs.map +1 -0
- package/dist/features/aggregation/aggregationFeature.d.cts +10 -0
- package/dist/features/aggregation/aggregationFeature.d.ts +10 -0
- package/dist/features/aggregation/aggregationFeature.js +38 -0
- package/dist/features/aggregation/aggregationFeature.js.map +1 -0
- package/dist/features/aggregation/aggregationFeature.types.cjs +13 -0
- package/dist/features/aggregation/aggregationFeature.types.cjs.map +1 -0
- package/dist/features/aggregation/aggregationFeature.types.d.cts +172 -0
- package/dist/features/aggregation/aggregationFeature.types.d.ts +172 -0
- package/dist/features/aggregation/aggregationFeature.types.js +12 -0
- package/dist/features/aggregation/aggregationFeature.types.js.map +1 -0
- package/dist/features/aggregation/aggregationFeature.utils.cjs +198 -0
- package/dist/features/aggregation/aggregationFeature.utils.cjs.map +1 -0
- package/dist/features/aggregation/aggregationFeature.utils.d.cts +33 -0
- package/dist/features/aggregation/aggregationFeature.utils.d.ts +33 -0
- package/dist/features/aggregation/aggregationFeature.utils.js +192 -0
- package/dist/features/aggregation/aggregationFeature.utils.js.map +1 -0
- package/dist/features/aggregation/aggregationFns.cjs +240 -0
- package/dist/features/aggregation/aggregationFns.cjs.map +1 -0
- package/dist/features/aggregation/aggregationFns.d.cts +67 -0
- package/dist/features/aggregation/aggregationFns.d.ts +67 -0
- package/dist/features/aggregation/aggregationFns.js +229 -0
- package/dist/features/aggregation/aggregationFns.js.map +1 -0
- package/dist/features/column-filtering/columnFilteringFeature.types.d.cts +43 -3
- package/dist/features/column-filtering/columnFilteringFeature.types.d.ts +43 -3
- package/dist/features/column-filtering/columnFilteringFeature.utils.cjs +18 -9
- package/dist/features/column-filtering/columnFilteringFeature.utils.cjs.map +1 -1
- package/dist/features/column-filtering/columnFilteringFeature.utils.d.cts +6 -2
- package/dist/features/column-filtering/columnFilteringFeature.utils.d.ts +6 -2
- package/dist/features/column-filtering/columnFilteringFeature.utils.js +18 -9
- package/dist/features/column-filtering/columnFilteringFeature.utils.js.map +1 -1
- package/dist/features/column-filtering/createFilteredRowModel.cjs +7 -2
- package/dist/features/column-filtering/createFilteredRowModel.cjs.map +1 -1
- package/dist/features/column-filtering/createFilteredRowModel.d.cts +6 -2
- package/dist/features/column-filtering/createFilteredRowModel.d.ts +6 -2
- package/dist/features/column-filtering/createFilteredRowModel.js +7 -2
- package/dist/features/column-filtering/createFilteredRowModel.js.map +1 -1
- package/dist/features/column-filtering/filterFns.cjs +399 -0
- package/dist/features/column-filtering/filterFns.cjs.map +1 -0
- package/dist/features/column-filtering/filterFns.d.cts +210 -0
- package/dist/features/column-filtering/filterFns.d.ts +210 -0
- package/dist/features/column-filtering/filterFns.js +375 -0
- package/dist/features/column-filtering/filterFns.js.map +1 -0
- package/dist/features/column-grouping/columnGroupingFeature.cjs +3 -12
- package/dist/features/column-grouping/columnGroupingFeature.cjs.map +1 -1
- package/dist/features/column-grouping/columnGroupingFeature.d.cts +1 -1
- package/dist/features/column-grouping/columnGroupingFeature.d.ts +1 -1
- package/dist/features/column-grouping/columnGroupingFeature.js +4 -13
- package/dist/features/column-grouping/columnGroupingFeature.js.map +1 -1
- package/dist/features/column-grouping/columnGroupingFeature.types.d.cts +6 -49
- package/dist/features/column-grouping/columnGroupingFeature.types.d.ts +6 -49
- package/dist/features/column-grouping/columnGroupingFeature.utils.cjs +0 -50
- package/dist/features/column-grouping/columnGroupingFeature.utils.cjs.map +1 -1
- package/dist/features/column-grouping/columnGroupingFeature.utils.d.cts +2 -39
- package/dist/features/column-grouping/columnGroupingFeature.utils.d.ts +2 -39
- package/dist/features/column-grouping/columnGroupingFeature.utils.js +2 -49
- package/dist/features/column-grouping/columnGroupingFeature.utils.js.map +1 -1
- package/dist/features/column-grouping/createGroupedRowModel.cjs +23 -13
- package/dist/features/column-grouping/createGroupedRowModel.cjs.map +1 -1
- package/dist/features/column-grouping/createGroupedRowModel.d.cts +2 -3
- package/dist/features/column-grouping/createGroupedRowModel.d.ts +2 -3
- package/dist/features/column-grouping/createGroupedRowModel.js +25 -15
- package/dist/features/column-grouping/createGroupedRowModel.js.map +1 -1
- package/dist/features/global-filtering/globalFilteringFeature.utils.cjs +4 -2
- package/dist/features/global-filtering/globalFilteringFeature.utils.cjs.map +1 -1
- package/dist/features/global-filtering/globalFilteringFeature.utils.d.cts +2 -6
- package/dist/features/global-filtering/globalFilteringFeature.utils.d.ts +2 -6
- package/dist/features/global-filtering/globalFilteringFeature.utils.js +4 -2
- package/dist/features/global-filtering/globalFilteringFeature.utils.js.map +1 -1
- package/dist/features/row-sorting/createSortedRowModel.cjs +6 -2
- package/dist/features/row-sorting/createSortedRowModel.cjs.map +1 -1
- package/dist/features/row-sorting/createSortedRowModel.d.cts +6 -2
- package/dist/features/row-sorting/createSortedRowModel.d.ts +6 -2
- package/dist/features/row-sorting/createSortedRowModel.js +6 -2
- package/dist/features/row-sorting/createSortedRowModel.js.map +1 -1
- package/dist/features/row-sorting/rowSortingFeature.types.d.cts +32 -3
- package/dist/features/row-sorting/rowSortingFeature.types.d.ts +32 -3
- package/dist/features/row-sorting/rowSortingFeature.utils.cjs +20 -5
- package/dist/features/row-sorting/rowSortingFeature.utils.cjs.map +1 -1
- package/dist/features/row-sorting/rowSortingFeature.utils.js +20 -5
- package/dist/features/row-sorting/rowSortingFeature.utils.js.map +1 -1
- package/dist/{fns → features/row-sorting}/sortFns.cjs +69 -22
- package/dist/features/row-sorting/sortFns.cjs.map +1 -0
- package/dist/features/row-sorting/sortFns.d.cts +98 -0
- package/dist/features/row-sorting/sortFns.d.ts +98 -0
- package/dist/{fns → features/row-sorting}/sortFns.js +69 -23
- package/dist/features/row-sorting/sortFns.js.map +1 -0
- package/dist/features/stockFeatures.cjs +2 -0
- package/dist/features/stockFeatures.cjs.map +1 -1
- package/dist/features/stockFeatures.d.cts +2 -0
- package/dist/features/stockFeatures.d.ts +2 -0
- package/dist/features/stockFeatures.js +2 -0
- package/dist/features/stockFeatures.js.map +1 -1
- package/dist/helpers/tableFeatures.cjs +5 -4
- package/dist/helpers/tableFeatures.cjs.map +1 -1
- package/dist/helpers/tableFeatures.d.cts +5 -4
- package/dist/helpers/tableFeatures.d.ts +5 -4
- package/dist/helpers/tableFeatures.js +5 -4
- package/dist/helpers/tableFeatures.js.map +1 -1
- package/dist/index.cjs +18 -3
- package/dist/index.d.cts +10 -8
- package/dist/index.d.ts +10 -8
- package/dist/index.js +6 -4
- package/dist/static-functions.cjs +8 -3
- package/dist/static-functions.d.cts +3 -2
- package/dist/static-functions.d.ts +3 -2
- package/dist/static-functions.js +3 -2
- package/dist/types/Cell.d.cts +3 -1
- package/dist/types/Cell.d.ts +3 -1
- package/dist/types/Column.d.cts +4 -2
- package/dist/types/Column.d.ts +4 -2
- package/dist/types/ColumnDef.d.cts +5 -3
- package/dist/types/ColumnDef.d.ts +5 -3
- package/dist/types/Row.d.cts +3 -1
- package/dist/types/Row.d.ts +3 -1
- package/dist/types/RowModel.d.cts +1 -1
- package/dist/types/RowModel.d.ts +1 -1
- package/dist/types/RowModelFns.d.cts +3 -3
- package/dist/types/RowModelFns.d.ts +3 -3
- package/dist/types/Table.d.cts +1 -1
- package/dist/types/Table.d.ts +1 -1
- package/dist/types/TableFeatures.d.cts +19 -11
- package/dist/types/TableFeatures.d.ts +19 -11
- package/dist/types/TableOptions.d.cts +5 -3
- package/dist/types/TableOptions.d.ts +5 -3
- package/dist/types/TableState.d.cts +1 -1
- package/dist/types/TableState.d.ts +1 -1
- package/dist/types/type-utils.d.cts +8 -1
- package/dist/types/type-utils.d.ts +8 -1
- package/dist/worker/initTableWorker.cjs.map +1 -1
- package/dist/worker/initTableWorker.js.map +1 -1
- package/package.json +1 -1
- package/skills/aggregation/SKILL.md +131 -0
- package/skills/api-not-found/SKILL.md +1 -1
- package/skills/client-vs-server/SKILL.md +1 -1
- package/skills/column-faceting/SKILL.md +11 -5
- package/skills/column-filtering/SKILL.md +8 -3
- 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 +3 -3
- package/skills/grouping/SKILL.md +12 -13
- package/skills/migrate-v8-to-v9/SKILL.md +21 -8
- 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 +9 -3
- package/skills/table-features/SKILL.md +19 -13
- package/skills/typescript/SKILL.md +1 -1
- package/src/core/row-models/coreRowModelsFeature.utils.ts +1 -1
- package/src/features/aggregation/aggregationFeature.ts +59 -0
- package/src/features/aggregation/aggregationFeature.types.ts +312 -0
- package/src/features/aggregation/aggregationFeature.utils.ts +401 -0
- package/src/features/aggregation/aggregationFns.ts +336 -0
- package/src/features/column-filtering/columnFilteringFeature.types.ts +61 -1
- package/src/features/column-filtering/columnFilteringFeature.utils.ts +33 -19
- package/src/features/column-filtering/createFilteredRowModel.ts +13 -3
- package/src/features/column-filtering/filterFns.ts +533 -0
- package/src/features/column-grouping/columnGroupingFeature.ts +1 -20
- package/src/features/column-grouping/columnGroupingFeature.types.ts +4 -86
- package/src/features/column-grouping/columnGroupingFeature.utils.ts +1 -88
- package/src/features/column-grouping/createGroupedRowModel.ts +32 -38
- package/src/features/global-filtering/globalFilteringFeature.utils.ts +9 -1
- package/src/features/row-sorting/createSortedRowModel.ts +6 -2
- package/src/features/row-sorting/rowSortingFeature.types.ts +54 -2
- package/src/features/row-sorting/rowSortingFeature.utils.ts +46 -14
- package/src/{fns → features/row-sorting}/sortFns.ts +95 -81
- package/src/features/stockFeatures.ts +3 -0
- package/src/helpers/tableFeatures.ts +5 -4
- package/src/index.ts +7 -8
- package/src/static-functions.ts +1 -0
- package/src/types/Cell.ts +2 -0
- package/src/types/Column.ts +3 -1
- package/src/types/ColumnDef.ts +6 -3
- package/src/types/Row.ts +2 -0
- package/src/types/RowModelFns.ts +3 -3
- package/src/types/TableFeatures.ts +19 -11
- package/src/types/TableOptions.ts +5 -1
- package/src/types/type-utils.ts +8 -0
- package/src/worker/initTableWorker.ts +1 -1
- package/dist/fns/aggregationFns.cjs +0 -163
- package/dist/fns/aggregationFns.cjs.map +0 -1
- package/dist/fns/aggregationFns.d.cts +0 -85
- package/dist/fns/aggregationFns.d.ts +0 -85
- package/dist/fns/aggregationFns.js +0 -153
- package/dist/fns/aggregationFns.js.map +0 -1
- package/dist/fns/filterFns.cjs +0 -242
- package/dist/fns/filterFns.cjs.map +0 -1
- package/dist/fns/filterFns.d.cts +0 -178
- package/dist/fns/filterFns.d.ts +0 -178
- package/dist/fns/filterFns.js +0 -226
- package/dist/fns/filterFns.js.map +0 -1
- package/dist/fns/sortFns.cjs.map +0 -1
- package/dist/fns/sortFns.d.cts +0 -65
- package/dist/fns/sortFns.d.ts +0 -65
- package/dist/fns/sortFns.js.map +0 -1
- package/src/fns/aggregationFns.ts +0 -245
- package/src/fns/filterFns.ts +0 -455
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import { constructAggregationFn } from './aggregationFeature.types'
|
|
2
|
+
import type { AggregationContext } from './aggregationFeature.types'
|
|
3
|
+
|
|
4
|
+
type RangeValue = Date | number
|
|
5
|
+
|
|
6
|
+
function isNumber(value: unknown): value is number {
|
|
7
|
+
return typeof value === 'number'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function isValidDate(value: unknown): value is Date {
|
|
11
|
+
return value instanceof Date && !Number.isNaN(value.getTime())
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function getRangeKind(value: unknown): 'date' | 'number' | undefined {
|
|
15
|
+
if (isNumber(value)) return 'number'
|
|
16
|
+
if (isValidDate(value)) return 'date'
|
|
17
|
+
return undefined
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function compareRangeValues(left: RangeValue, right: RangeValue) {
|
|
21
|
+
const leftValue = left instanceof Date ? left.getTime() : left
|
|
22
|
+
const rightValue = right instanceof Date ? right.getTime() : right
|
|
23
|
+
return leftValue - rightValue
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function collectRangeValues(context: AggregationContext<any, any, unknown>) {
|
|
27
|
+
const values: Array<RangeValue> = []
|
|
28
|
+
let kind: 'date' | 'number' | undefined
|
|
29
|
+
|
|
30
|
+
for (let i = 0; i < context.rows.length; i++) {
|
|
31
|
+
const value = context.getValue(context.rows[i]!)
|
|
32
|
+
const valueKind = getRangeKind(value)
|
|
33
|
+
if (!valueKind) continue
|
|
34
|
+
kind ??= valueKind
|
|
35
|
+
if (valueKind === kind) values.push(value as RangeValue)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return values
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Sums numeric row values. Non-number values contribute zero. As in the
|
|
43
|
+
* previous API, `NaN` is a number and therefore propagates through the sum.
|
|
44
|
+
*/
|
|
45
|
+
export const aggregationFn_sum = constructAggregationFn<
|
|
46
|
+
any,
|
|
47
|
+
any,
|
|
48
|
+
unknown,
|
|
49
|
+
number
|
|
50
|
+
>({
|
|
51
|
+
aggregate: (context) => {
|
|
52
|
+
let sum = 0
|
|
53
|
+
for (let i = 0; i < context.rows.length; i++) {
|
|
54
|
+
const value = context.getValue(context.rows[i]!)
|
|
55
|
+
sum += typeof value === 'number' ? value : 0
|
|
56
|
+
}
|
|
57
|
+
return sum
|
|
58
|
+
},
|
|
59
|
+
merge: ({ childResults }) => {
|
|
60
|
+
let sum = 0
|
|
61
|
+
for (let i = 0; i < childResults.length; i++) {
|
|
62
|
+
const value = childResults[i]
|
|
63
|
+
if (isNumber(value)) sum += value
|
|
64
|
+
}
|
|
65
|
+
return sum
|
|
66
|
+
},
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Finds the minimum numeric or Date value. Invalid value types are ignored;
|
|
71
|
+
* `NaN` preserves the legacy numeric seeding behavior.
|
|
72
|
+
*/
|
|
73
|
+
export const aggregationFn_min = constructAggregationFn<
|
|
74
|
+
any,
|
|
75
|
+
any,
|
|
76
|
+
unknown,
|
|
77
|
+
RangeValue | undefined
|
|
78
|
+
>({
|
|
79
|
+
aggregate: (context) => {
|
|
80
|
+
const values = collectRangeValues(context)
|
|
81
|
+
let result = values[0]
|
|
82
|
+
for (let i = 1; i < values.length; i++) {
|
|
83
|
+
if (compareRangeValues(values[i]!, result!) < 0) result = values[i]
|
|
84
|
+
}
|
|
85
|
+
return result
|
|
86
|
+
},
|
|
87
|
+
merge: ({ childResults }) => {
|
|
88
|
+
let result: RangeValue | undefined
|
|
89
|
+
let kind: 'date' | 'number' | undefined
|
|
90
|
+
for (let i = 0; i < childResults.length; i++) {
|
|
91
|
+
const value = childResults[i]
|
|
92
|
+
const valueKind = getRangeKind(value)
|
|
93
|
+
if (!valueKind) continue
|
|
94
|
+
kind ??= valueKind
|
|
95
|
+
if (kind !== valueKind) continue
|
|
96
|
+
if (result === undefined || compareRangeValues(value!, result) < 0) {
|
|
97
|
+
result = value
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return result
|
|
101
|
+
},
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Finds the maximum numeric or Date value. Invalid value types are ignored;
|
|
106
|
+
* `NaN` preserves the legacy numeric seeding behavior.
|
|
107
|
+
*/
|
|
108
|
+
export const aggregationFn_max = constructAggregationFn<
|
|
109
|
+
any,
|
|
110
|
+
any,
|
|
111
|
+
unknown,
|
|
112
|
+
RangeValue | undefined
|
|
113
|
+
>({
|
|
114
|
+
aggregate: (context) => {
|
|
115
|
+
const values = collectRangeValues(context)
|
|
116
|
+
let result = values[0]
|
|
117
|
+
for (let i = 1; i < values.length; i++) {
|
|
118
|
+
if (compareRangeValues(values[i]!, result!) > 0) result = values[i]
|
|
119
|
+
}
|
|
120
|
+
return result
|
|
121
|
+
},
|
|
122
|
+
merge: ({ childResults }) => {
|
|
123
|
+
let result: RangeValue | undefined
|
|
124
|
+
let kind: 'date' | 'number' | undefined
|
|
125
|
+
for (let i = 0; i < childResults.length; i++) {
|
|
126
|
+
const value = childResults[i]
|
|
127
|
+
const valueKind = getRangeKind(value)
|
|
128
|
+
if (!valueKind) continue
|
|
129
|
+
kind ??= valueKind
|
|
130
|
+
if (kind !== valueKind) continue
|
|
131
|
+
if (result === undefined || compareRangeValues(value!, result) > 0) {
|
|
132
|
+
result = value
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return result
|
|
136
|
+
},
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Finds the minimum and maximum numeric or Date values. Empty inputs return
|
|
141
|
+
* `[undefined, undefined]`, preserving the previous built-in result shape.
|
|
142
|
+
*/
|
|
143
|
+
export const aggregationFn_extent = constructAggregationFn<
|
|
144
|
+
any,
|
|
145
|
+
any,
|
|
146
|
+
unknown,
|
|
147
|
+
[RangeValue | undefined, RangeValue | undefined]
|
|
148
|
+
>({
|
|
149
|
+
aggregate: (context) => {
|
|
150
|
+
const values = collectRangeValues(context)
|
|
151
|
+
if (!values.length) return [undefined, undefined]
|
|
152
|
+
let min = values[0]!
|
|
153
|
+
let max = values[0]!
|
|
154
|
+
for (let i = 1; i < values.length; i++) {
|
|
155
|
+
const value = values[i]!
|
|
156
|
+
if (compareRangeValues(value, min) < 0) min = value
|
|
157
|
+
if (compareRangeValues(value, max) > 0) max = value
|
|
158
|
+
}
|
|
159
|
+
return [min, max]
|
|
160
|
+
},
|
|
161
|
+
merge: ({ childResults }) => {
|
|
162
|
+
let result: [RangeValue | undefined, RangeValue | undefined] = [
|
|
163
|
+
undefined,
|
|
164
|
+
undefined,
|
|
165
|
+
]
|
|
166
|
+
let kind: 'date' | 'number' | undefined
|
|
167
|
+
for (let i = 0; i < childResults.length; i++) {
|
|
168
|
+
const extent = childResults[i]!
|
|
169
|
+
const valueKind = getRangeKind(extent[0])
|
|
170
|
+
if (!valueKind) continue
|
|
171
|
+
kind ??= valueKind
|
|
172
|
+
if (kind !== valueKind) continue
|
|
173
|
+
if (result[0] === undefined) {
|
|
174
|
+
result = [extent[0], extent[1]]
|
|
175
|
+
} else {
|
|
176
|
+
if (compareRangeValues(extent[0]!, result[0]) < 0) {
|
|
177
|
+
result[0] = extent[0]
|
|
178
|
+
}
|
|
179
|
+
if (compareRangeValues(extent[1]!, result[1]!) > 0) {
|
|
180
|
+
result[1] = extent[1]
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return result
|
|
185
|
+
},
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Averages number and number-like row values. Nullish and non-numeric values
|
|
190
|
+
* are ignored; other values retain the legacy unary-plus coercion behavior.
|
|
191
|
+
*/
|
|
192
|
+
export const aggregationFn_mean = constructAggregationFn<
|
|
193
|
+
any,
|
|
194
|
+
any,
|
|
195
|
+
unknown,
|
|
196
|
+
number | undefined
|
|
197
|
+
>({
|
|
198
|
+
aggregate: (context) => {
|
|
199
|
+
let count = 0
|
|
200
|
+
let sum = 0
|
|
201
|
+
for (let i = 0; i < context.rows.length; i++) {
|
|
202
|
+
const value = context.getValue(context.rows[i]!)
|
|
203
|
+
if (value == null) continue
|
|
204
|
+
const numberValue = typeof value === 'number' ? value : +value
|
|
205
|
+
if (!Number.isNaN(numberValue)) {
|
|
206
|
+
count++
|
|
207
|
+
sum += numberValue
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return count ? sum / count : undefined
|
|
211
|
+
},
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Computes the median when every row value is a number. Returns `undefined`
|
|
216
|
+
* for empty inputs or when any value is non-numeric.
|
|
217
|
+
*/
|
|
218
|
+
export const aggregationFn_median = constructAggregationFn<
|
|
219
|
+
any,
|
|
220
|
+
any,
|
|
221
|
+
unknown,
|
|
222
|
+
number | undefined
|
|
223
|
+
>({
|
|
224
|
+
aggregate: (context) => {
|
|
225
|
+
if (!context.rows.length) return undefined
|
|
226
|
+
const values = new Array<number>(context.rows.length)
|
|
227
|
+
for (let i = 0; i < context.rows.length; i++) {
|
|
228
|
+
const value = context.getValue(context.rows[i]!)
|
|
229
|
+
if (typeof value !== 'number') return undefined
|
|
230
|
+
values[i] = value
|
|
231
|
+
}
|
|
232
|
+
values.sort((a, b) => a - b)
|
|
233
|
+
const mid = Math.floor(values.length / 2)
|
|
234
|
+
return values.length % 2
|
|
235
|
+
? values[mid]
|
|
236
|
+
: (values[mid - 1]! + values[mid]!) / 2
|
|
237
|
+
},
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
/** Collects distinct row values using JavaScript `Set` semantics. */
|
|
241
|
+
export const aggregationFn_unique = constructAggregationFn<
|
|
242
|
+
any,
|
|
243
|
+
any,
|
|
244
|
+
unknown,
|
|
245
|
+
Array<unknown>
|
|
246
|
+
>({
|
|
247
|
+
aggregate: (context) => {
|
|
248
|
+
const values = new Set<unknown>()
|
|
249
|
+
for (let i = 0; i < context.rows.length; i++) {
|
|
250
|
+
values.add(context.getValue(context.rows[i]!))
|
|
251
|
+
}
|
|
252
|
+
return Array.from(values)
|
|
253
|
+
},
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
/** Counts distinct row values using JavaScript `Set` semantics. */
|
|
257
|
+
export const aggregationFn_uniqueCount = constructAggregationFn<
|
|
258
|
+
any,
|
|
259
|
+
any,
|
|
260
|
+
unknown,
|
|
261
|
+
number
|
|
262
|
+
>({
|
|
263
|
+
aggregate: (context) => {
|
|
264
|
+
const values = new Set<unknown>()
|
|
265
|
+
for (let i = 0; i < context.rows.length; i++) {
|
|
266
|
+
values.add(context.getValue(context.rows[i]!))
|
|
267
|
+
}
|
|
268
|
+
return values.size
|
|
269
|
+
},
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
/** Counts rows, independently of the column's values. */
|
|
273
|
+
export const aggregationFn_count = constructAggregationFn<
|
|
274
|
+
any,
|
|
275
|
+
any,
|
|
276
|
+
unknown,
|
|
277
|
+
number
|
|
278
|
+
>({
|
|
279
|
+
aggregate: ({ rows }) => rows.length,
|
|
280
|
+
merge: ({ childResults }) => {
|
|
281
|
+
let count = 0
|
|
282
|
+
for (let i = 0; i < childResults.length; i++) {
|
|
283
|
+
const value = childResults[i]
|
|
284
|
+
if (isNumber(value)) count += value
|
|
285
|
+
}
|
|
286
|
+
return count
|
|
287
|
+
},
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
/** Returns the first row's value, including a nullish value. */
|
|
291
|
+
export const aggregationFn_first = constructAggregationFn<
|
|
292
|
+
any,
|
|
293
|
+
any,
|
|
294
|
+
unknown,
|
|
295
|
+
unknown
|
|
296
|
+
>({
|
|
297
|
+
aggregate: (context) =>
|
|
298
|
+
context.rows[0] ? context.getValue(context.rows[0]) : undefined,
|
|
299
|
+
merge: ({ childResults }) => childResults[0],
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
/** Returns the last row's value, including a nullish value. */
|
|
303
|
+
export const aggregationFn_last = constructAggregationFn<
|
|
304
|
+
any,
|
|
305
|
+
any,
|
|
306
|
+
unknown,
|
|
307
|
+
unknown
|
|
308
|
+
>({
|
|
309
|
+
aggregate: (context) => {
|
|
310
|
+
const row = context.rows[context.rows.length - 1]
|
|
311
|
+
return row ? context.getValue(row) : undefined
|
|
312
|
+
},
|
|
313
|
+
merge: ({ childResults }) => childResults[childResults.length - 1],
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Full built-in registry. Register individual definitions for tree-shaking.
|
|
318
|
+
*
|
|
319
|
+
* @deprecated Import individual `aggregationFn_*` definitions instead for a
|
|
320
|
+
* smaller bundle. This registry remains available for compatibility.
|
|
321
|
+
*/
|
|
322
|
+
export const aggregationFns = {
|
|
323
|
+
sum: aggregationFn_sum,
|
|
324
|
+
min: aggregationFn_min,
|
|
325
|
+
max: aggregationFn_max,
|
|
326
|
+
extent: aggregationFn_extent,
|
|
327
|
+
mean: aggregationFn_mean,
|
|
328
|
+
median: aggregationFn_median,
|
|
329
|
+
unique: aggregationFn_unique,
|
|
330
|
+
uniqueCount: aggregationFn_uniqueCount,
|
|
331
|
+
count: aggregationFn_count,
|
|
332
|
+
first: aggregationFn_first,
|
|
333
|
+
last: aggregationFn_last,
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export type BuiltInAggregationFn = keyof typeof aggregationFns
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { BuiltInFilterFn } from '
|
|
1
|
+
import type { BuiltInFilterFn } from './filterFns'
|
|
2
2
|
import type {
|
|
3
3
|
CellData,
|
|
4
4
|
OnChangeFn,
|
|
5
5
|
RowData,
|
|
6
|
+
TransformDataValueFn,
|
|
6
7
|
Updater,
|
|
7
8
|
} from '../../types/type-utils'
|
|
8
9
|
import type { IsAny, TableFeatures } from '../../types/TableFeatures'
|
|
@@ -66,8 +67,67 @@ export interface FilterFn<
|
|
|
66
67
|
filterValue: any,
|
|
67
68
|
addMeta?: (meta: ExtractFilterMeta<TFeatures>) => void,
|
|
68
69
|
): boolean
|
|
70
|
+
/**
|
|
71
|
+
* Removes the filter from `state.columnFilters` when the filter value fails
|
|
72
|
+
* this test (e.g. empty strings for text filters).
|
|
73
|
+
*/
|
|
69
74
|
autoRemove?: ColumnFilterAutoRemoveTestFn<TFeatures, TData>
|
|
75
|
+
/**
|
|
76
|
+
* Normalizes the filter value before filtering runs.
|
|
77
|
+
*
|
|
78
|
+
* The table applies this once per filter (not per row) and passes the
|
|
79
|
+
* resolved value to the filter function as `filterValue`.
|
|
80
|
+
*/
|
|
70
81
|
resolveFilterValue?: TransformFilterValueFn<TFeatures, TData>
|
|
82
|
+
/**
|
|
83
|
+
* Normalizes each row's value before it is compared against the filter
|
|
84
|
+
* value. Only honored by filter functions built with `constructFilterFn`
|
|
85
|
+
* (including all built-in filter functions).
|
|
86
|
+
*/
|
|
87
|
+
resolveDataValue?: TransformDataValueFn
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The definition object accepted by `constructFilterFn`.
|
|
92
|
+
*
|
|
93
|
+
* `filter` is a value-level comparator: it receives the row's (resolved) data
|
|
94
|
+
* value and the (resolved) filter value instead of the whole row, so
|
|
95
|
+
* normalization concerns stay in `resolveDataValue`/`resolveFilterValue`.
|
|
96
|
+
*/
|
|
97
|
+
export interface FilterFnDef<
|
|
98
|
+
in out TFeatures extends TableFeatures,
|
|
99
|
+
in out TData extends RowData,
|
|
100
|
+
> {
|
|
101
|
+
filter: (
|
|
102
|
+
dataValue: any,
|
|
103
|
+
filterValue: any,
|
|
104
|
+
row: Row<TFeatures, TData>,
|
|
105
|
+
columnId: string,
|
|
106
|
+
addMeta?: (meta: ExtractFilterMeta<TFeatures>) => void,
|
|
107
|
+
) => boolean
|
|
108
|
+
autoRemove?: (filterValue: any) => boolean
|
|
109
|
+
resolveFilterValue?: (filterValue: any) => any
|
|
110
|
+
resolveDataValue?: TransformDataValueFn
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The shape returned by `constructFilterFn`: a `FilterFn` with its definition
|
|
115
|
+
* attached, so variants can be built by spreading it into another
|
|
116
|
+
* `constructFilterFn` call.
|
|
117
|
+
*
|
|
118
|
+
* The call signature is generic so a created filter function can be used with
|
|
119
|
+
* any table's rows, regardless of the feature set it was defined against.
|
|
120
|
+
*/
|
|
121
|
+
export interface CreatedFilterFn<
|
|
122
|
+
in out TFeatures extends TableFeatures,
|
|
123
|
+
in out TData extends RowData,
|
|
124
|
+
> extends FilterFnDef<TFeatures, TData> {
|
|
125
|
+
<TRowFeatures extends TableFeatures, TRowData extends RowData>(
|
|
126
|
+
row: Row<TRowFeatures, TRowData>,
|
|
127
|
+
columnId: string,
|
|
128
|
+
filterValue: any,
|
|
129
|
+
addMeta?: (meta: ExtractFilterMeta<TRowFeatures>) => void,
|
|
130
|
+
): boolean
|
|
71
131
|
}
|
|
72
132
|
|
|
73
133
|
export type TransformFilterValueFn<
|
|
@@ -27,8 +27,12 @@ export function getDefaultColumnFiltersState(): ColumnFiltersState {
|
|
|
27
27
|
* Chooses a built-in filter function from the column's first core row value.
|
|
28
28
|
*
|
|
29
29
|
* Strings use `includesString`, numbers use `inNumberRange`, booleans and
|
|
30
|
-
* objects use `equals`,
|
|
31
|
-
* to `weakEquals`.
|
|
30
|
+
* objects use `equals`, dates use `inDateRange`, arrays use `arrIncludes`,
|
|
31
|
+
* and unknown values fall back to `weakEquals`.
|
|
32
|
+
*
|
|
33
|
+
* The chosen filter function is looked up in the table's `filterFns`
|
|
34
|
+
* registry. When it is not registered there, this returns `undefined` and
|
|
35
|
+
* warns in development instead of substituting a different filter function.
|
|
32
36
|
*
|
|
33
37
|
* @example
|
|
34
38
|
* ```ts
|
|
@@ -47,27 +51,33 @@ export function column_getAutoFilterFn<
|
|
|
47
51
|
|
|
48
52
|
const value = firstRow ? firstRow.getValue(column.id) : undefined
|
|
49
53
|
|
|
50
|
-
|
|
51
|
-
return filterFns?.includesString
|
|
52
|
-
}
|
|
54
|
+
let filterFnName: string
|
|
53
55
|
|
|
54
|
-
if (typeof value === '
|
|
55
|
-
|
|
56
|
+
if (typeof value === 'string') {
|
|
57
|
+
filterFnName = 'includesString'
|
|
58
|
+
} else if (typeof value === 'number') {
|
|
59
|
+
filterFnName = 'inNumberRange'
|
|
60
|
+
} else if (typeof value === 'boolean') {
|
|
61
|
+
filterFnName = 'equals'
|
|
62
|
+
} else if (Array.isArray(value)) {
|
|
63
|
+
filterFnName = 'arrIncludes'
|
|
64
|
+
} else if (Object.prototype.toString.call(value) === '[object Date]') {
|
|
65
|
+
filterFnName = 'inDateRange'
|
|
66
|
+
} else if (value !== null && typeof value === 'object') {
|
|
67
|
+
filterFnName = 'equals'
|
|
68
|
+
} else {
|
|
69
|
+
filterFnName = 'weakEquals'
|
|
56
70
|
}
|
|
57
71
|
|
|
58
|
-
|
|
59
|
-
return filterFns?.equals
|
|
60
|
-
}
|
|
72
|
+
const filterFn = filterFns?.[filterFnName]
|
|
61
73
|
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (value !== null && typeof value === 'object') {
|
|
67
|
-
return filterFns?.equals
|
|
74
|
+
if (process.env.NODE_ENV === 'development' && !filterFn) {
|
|
75
|
+
console.warn(
|
|
76
|
+
`filterFn '${filterFnName}' (auto) for column '${column.id}' is not registered`,
|
|
77
|
+
)
|
|
68
78
|
}
|
|
69
79
|
|
|
70
|
-
return
|
|
80
|
+
return filterFn
|
|
71
81
|
}
|
|
72
82
|
|
|
73
83
|
/**
|
|
@@ -98,9 +108,13 @@ export function column_getFilterFn<
|
|
|
98
108
|
? column_getAutoFilterFn(column)
|
|
99
109
|
: filterFns?.[column.columnDef.filterFn as string]
|
|
100
110
|
|
|
101
|
-
if (
|
|
111
|
+
if (
|
|
112
|
+
process.env.NODE_ENV === 'development' &&
|
|
113
|
+
!filterFn &&
|
|
114
|
+
column.columnDef.filterFn !== 'auto' // the auto picker warns on its own
|
|
115
|
+
) {
|
|
102
116
|
console.warn(
|
|
103
|
-
`
|
|
117
|
+
`filterFn '${String(column.columnDef.filterFn)}' for column '${column.id}' is not registered`,
|
|
104
118
|
)
|
|
105
119
|
}
|
|
106
120
|
|
|
@@ -22,8 +22,12 @@ import type {
|
|
|
22
22
|
*
|
|
23
23
|
* The factory reads the relevant table state atoms and options, then returns a row model function used by the table row-model pipeline.
|
|
24
24
|
*
|
|
25
|
-
* Register filter functions with the `filterFns` slot on the
|
|
26
|
-
* `
|
|
25
|
+
* Register the filter functions you use with the `filterFns` slot on the
|
|
26
|
+
* `features` option:
|
|
27
|
+
* `tableFeatures({ columnFilteringFeature, filteredRowModel: createFilteredRowModel(), filterFns: { includesString: filterFn_includesString } })`.
|
|
28
|
+
* Importing individual `filterFn_*` functions keeps unused built-ins out of
|
|
29
|
+
* your bundle; filter functions passed directly to the `filterFn` column
|
|
30
|
+
* option need no registration at all.
|
|
27
31
|
*/
|
|
28
32
|
export function createFilteredRowModel<
|
|
29
33
|
TFeatures extends TableFeatures,
|
|
@@ -78,7 +82,13 @@ function _createFilteredRowModel<
|
|
|
78
82
|
return
|
|
79
83
|
}
|
|
80
84
|
|
|
81
|
-
const filterFn = column_getFilterFn(column)
|
|
85
|
+
const filterFn = column_getFilterFn(column)
|
|
86
|
+
|
|
87
|
+
// A dev warning has already fired in column_getFilterFn; ignore the
|
|
88
|
+
// filter instead of crashing when its filter fn is not registered.
|
|
89
|
+
if (!filterFn) {
|
|
90
|
+
return
|
|
91
|
+
}
|
|
82
92
|
|
|
83
93
|
resolvedColumnFilters.push({
|
|
84
94
|
id: columnFilter.id,
|