@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.
Files changed (212) hide show
  1. package/dist/core/row-models/coreRowModelsFeature.types.d.cts +1 -1
  2. package/dist/core/row-models/coreRowModelsFeature.types.d.ts +1 -1
  3. package/dist/core/row-models/coreRowModelsFeature.utils.cjs +1 -1
  4. package/dist/core/row-models/coreRowModelsFeature.utils.cjs.map +1 -1
  5. package/dist/core/row-models/coreRowModelsFeature.utils.d.cts +1 -1
  6. package/dist/core/row-models/coreRowModelsFeature.utils.d.ts +1 -1
  7. package/dist/core/row-models/coreRowModelsFeature.utils.js +1 -1
  8. package/dist/core/row-models/coreRowModelsFeature.utils.js.map +1 -1
  9. package/dist/features/aggregation/aggregationFeature.cjs +38 -0
  10. package/dist/features/aggregation/aggregationFeature.cjs.map +1 -0
  11. package/dist/features/aggregation/aggregationFeature.d.cts +10 -0
  12. package/dist/features/aggregation/aggregationFeature.d.ts +10 -0
  13. package/dist/features/aggregation/aggregationFeature.js +38 -0
  14. package/dist/features/aggregation/aggregationFeature.js.map +1 -0
  15. package/dist/features/aggregation/aggregationFeature.types.cjs +13 -0
  16. package/dist/features/aggregation/aggregationFeature.types.cjs.map +1 -0
  17. package/dist/features/aggregation/aggregationFeature.types.d.cts +172 -0
  18. package/dist/features/aggregation/aggregationFeature.types.d.ts +172 -0
  19. package/dist/features/aggregation/aggregationFeature.types.js +12 -0
  20. package/dist/features/aggregation/aggregationFeature.types.js.map +1 -0
  21. package/dist/features/aggregation/aggregationFeature.utils.cjs +198 -0
  22. package/dist/features/aggregation/aggregationFeature.utils.cjs.map +1 -0
  23. package/dist/features/aggregation/aggregationFeature.utils.d.cts +33 -0
  24. package/dist/features/aggregation/aggregationFeature.utils.d.ts +33 -0
  25. package/dist/features/aggregation/aggregationFeature.utils.js +192 -0
  26. package/dist/features/aggregation/aggregationFeature.utils.js.map +1 -0
  27. package/dist/features/aggregation/aggregationFns.cjs +240 -0
  28. package/dist/features/aggregation/aggregationFns.cjs.map +1 -0
  29. package/dist/features/aggregation/aggregationFns.d.cts +67 -0
  30. package/dist/features/aggregation/aggregationFns.d.ts +67 -0
  31. package/dist/features/aggregation/aggregationFns.js +229 -0
  32. package/dist/features/aggregation/aggregationFns.js.map +1 -0
  33. package/dist/features/column-filtering/columnFilteringFeature.types.d.cts +43 -3
  34. package/dist/features/column-filtering/columnFilteringFeature.types.d.ts +43 -3
  35. package/dist/features/column-filtering/columnFilteringFeature.utils.cjs +18 -9
  36. package/dist/features/column-filtering/columnFilteringFeature.utils.cjs.map +1 -1
  37. package/dist/features/column-filtering/columnFilteringFeature.utils.d.cts +6 -2
  38. package/dist/features/column-filtering/columnFilteringFeature.utils.d.ts +6 -2
  39. package/dist/features/column-filtering/columnFilteringFeature.utils.js +18 -9
  40. package/dist/features/column-filtering/columnFilteringFeature.utils.js.map +1 -1
  41. package/dist/features/column-filtering/createFilteredRowModel.cjs +7 -2
  42. package/dist/features/column-filtering/createFilteredRowModel.cjs.map +1 -1
  43. package/dist/features/column-filtering/createFilteredRowModel.d.cts +6 -2
  44. package/dist/features/column-filtering/createFilteredRowModel.d.ts +6 -2
  45. package/dist/features/column-filtering/createFilteredRowModel.js +7 -2
  46. package/dist/features/column-filtering/createFilteredRowModel.js.map +1 -1
  47. package/dist/features/column-filtering/filterFns.cjs +399 -0
  48. package/dist/features/column-filtering/filterFns.cjs.map +1 -0
  49. package/dist/features/column-filtering/filterFns.d.cts +210 -0
  50. package/dist/features/column-filtering/filterFns.d.ts +210 -0
  51. package/dist/features/column-filtering/filterFns.js +375 -0
  52. package/dist/features/column-filtering/filterFns.js.map +1 -0
  53. package/dist/features/column-grouping/columnGroupingFeature.cjs +3 -12
  54. package/dist/features/column-grouping/columnGroupingFeature.cjs.map +1 -1
  55. package/dist/features/column-grouping/columnGroupingFeature.d.cts +1 -1
  56. package/dist/features/column-grouping/columnGroupingFeature.d.ts +1 -1
  57. package/dist/features/column-grouping/columnGroupingFeature.js +4 -13
  58. package/dist/features/column-grouping/columnGroupingFeature.js.map +1 -1
  59. package/dist/features/column-grouping/columnGroupingFeature.types.d.cts +6 -49
  60. package/dist/features/column-grouping/columnGroupingFeature.types.d.ts +6 -49
  61. package/dist/features/column-grouping/columnGroupingFeature.utils.cjs +0 -50
  62. package/dist/features/column-grouping/columnGroupingFeature.utils.cjs.map +1 -1
  63. package/dist/features/column-grouping/columnGroupingFeature.utils.d.cts +2 -39
  64. package/dist/features/column-grouping/columnGroupingFeature.utils.d.ts +2 -39
  65. package/dist/features/column-grouping/columnGroupingFeature.utils.js +2 -49
  66. package/dist/features/column-grouping/columnGroupingFeature.utils.js.map +1 -1
  67. package/dist/features/column-grouping/createGroupedRowModel.cjs +23 -13
  68. package/dist/features/column-grouping/createGroupedRowModel.cjs.map +1 -1
  69. package/dist/features/column-grouping/createGroupedRowModel.d.cts +2 -3
  70. package/dist/features/column-grouping/createGroupedRowModel.d.ts +2 -3
  71. package/dist/features/column-grouping/createGroupedRowModel.js +25 -15
  72. package/dist/features/column-grouping/createGroupedRowModel.js.map +1 -1
  73. package/dist/features/global-filtering/globalFilteringFeature.utils.cjs +4 -2
  74. package/dist/features/global-filtering/globalFilteringFeature.utils.cjs.map +1 -1
  75. package/dist/features/global-filtering/globalFilteringFeature.utils.d.cts +2 -6
  76. package/dist/features/global-filtering/globalFilteringFeature.utils.d.ts +2 -6
  77. package/dist/features/global-filtering/globalFilteringFeature.utils.js +4 -2
  78. package/dist/features/global-filtering/globalFilteringFeature.utils.js.map +1 -1
  79. package/dist/features/row-sorting/createSortedRowModel.cjs +6 -2
  80. package/dist/features/row-sorting/createSortedRowModel.cjs.map +1 -1
  81. package/dist/features/row-sorting/createSortedRowModel.d.cts +6 -2
  82. package/dist/features/row-sorting/createSortedRowModel.d.ts +6 -2
  83. package/dist/features/row-sorting/createSortedRowModel.js +6 -2
  84. package/dist/features/row-sorting/createSortedRowModel.js.map +1 -1
  85. package/dist/features/row-sorting/rowSortingFeature.types.d.cts +32 -3
  86. package/dist/features/row-sorting/rowSortingFeature.types.d.ts +32 -3
  87. package/dist/features/row-sorting/rowSortingFeature.utils.cjs +20 -5
  88. package/dist/features/row-sorting/rowSortingFeature.utils.cjs.map +1 -1
  89. package/dist/features/row-sorting/rowSortingFeature.utils.js +20 -5
  90. package/dist/features/row-sorting/rowSortingFeature.utils.js.map +1 -1
  91. package/dist/{fns → features/row-sorting}/sortFns.cjs +69 -22
  92. package/dist/features/row-sorting/sortFns.cjs.map +1 -0
  93. package/dist/features/row-sorting/sortFns.d.cts +98 -0
  94. package/dist/features/row-sorting/sortFns.d.ts +98 -0
  95. package/dist/{fns → features/row-sorting}/sortFns.js +69 -23
  96. package/dist/features/row-sorting/sortFns.js.map +1 -0
  97. package/dist/features/stockFeatures.cjs +2 -0
  98. package/dist/features/stockFeatures.cjs.map +1 -1
  99. package/dist/features/stockFeatures.d.cts +2 -0
  100. package/dist/features/stockFeatures.d.ts +2 -0
  101. package/dist/features/stockFeatures.js +2 -0
  102. package/dist/features/stockFeatures.js.map +1 -1
  103. package/dist/helpers/tableFeatures.cjs +5 -4
  104. package/dist/helpers/tableFeatures.cjs.map +1 -1
  105. package/dist/helpers/tableFeatures.d.cts +5 -4
  106. package/dist/helpers/tableFeatures.d.ts +5 -4
  107. package/dist/helpers/tableFeatures.js +5 -4
  108. package/dist/helpers/tableFeatures.js.map +1 -1
  109. package/dist/index.cjs +18 -3
  110. package/dist/index.d.cts +10 -8
  111. package/dist/index.d.ts +10 -8
  112. package/dist/index.js +6 -4
  113. package/dist/static-functions.cjs +8 -3
  114. package/dist/static-functions.d.cts +3 -2
  115. package/dist/static-functions.d.ts +3 -2
  116. package/dist/static-functions.js +3 -2
  117. package/dist/types/Cell.d.cts +3 -1
  118. package/dist/types/Cell.d.ts +3 -1
  119. package/dist/types/Column.d.cts +4 -2
  120. package/dist/types/Column.d.ts +4 -2
  121. package/dist/types/ColumnDef.d.cts +5 -3
  122. package/dist/types/ColumnDef.d.ts +5 -3
  123. package/dist/types/Row.d.cts +3 -1
  124. package/dist/types/Row.d.ts +3 -1
  125. package/dist/types/RowModel.d.cts +1 -1
  126. package/dist/types/RowModel.d.ts +1 -1
  127. package/dist/types/RowModelFns.d.cts +3 -3
  128. package/dist/types/RowModelFns.d.ts +3 -3
  129. package/dist/types/Table.d.cts +1 -1
  130. package/dist/types/Table.d.ts +1 -1
  131. package/dist/types/TableFeatures.d.cts +19 -11
  132. package/dist/types/TableFeatures.d.ts +19 -11
  133. package/dist/types/TableOptions.d.cts +5 -3
  134. package/dist/types/TableOptions.d.ts +5 -3
  135. package/dist/types/TableState.d.cts +1 -1
  136. package/dist/types/TableState.d.ts +1 -1
  137. package/dist/types/type-utils.d.cts +8 -1
  138. package/dist/types/type-utils.d.ts +8 -1
  139. package/dist/worker/initTableWorker.cjs.map +1 -1
  140. package/dist/worker/initTableWorker.js.map +1 -1
  141. package/package.json +1 -1
  142. package/skills/aggregation/SKILL.md +131 -0
  143. package/skills/api-not-found/SKILL.md +1 -1
  144. package/skills/client-vs-server/SKILL.md +1 -1
  145. package/skills/column-faceting/SKILL.md +11 -5
  146. package/skills/column-filtering/SKILL.md +8 -3
  147. package/skills/column-ordering/SKILL.md +1 -1
  148. package/skills/column-pinning/SKILL.md +1 -1
  149. package/skills/column-resizing/SKILL.md +1 -1
  150. package/skills/column-sizing/SKILL.md +1 -1
  151. package/skills/column-visibility/SKILL.md +1 -1
  152. package/skills/core/SKILL.md +1 -1
  153. package/skills/custom-features/SKILL.md +1 -1
  154. package/skills/expanding/SKILL.md +1 -1
  155. package/skills/global-filtering/SKILL.md +3 -3
  156. package/skills/grouping/SKILL.md +12 -13
  157. package/skills/migrate-v8-to-v9/SKILL.md +21 -8
  158. package/skills/pagination/SKILL.md +1 -1
  159. package/skills/row-pinning/SKILL.md +1 -1
  160. package/skills/row-selection/SKILL.md +1 -1
  161. package/skills/sorting/SKILL.md +9 -3
  162. package/skills/table-features/SKILL.md +19 -13
  163. package/skills/typescript/SKILL.md +1 -1
  164. package/src/core/row-models/coreRowModelsFeature.utils.ts +1 -1
  165. package/src/features/aggregation/aggregationFeature.ts +59 -0
  166. package/src/features/aggregation/aggregationFeature.types.ts +312 -0
  167. package/src/features/aggregation/aggregationFeature.utils.ts +401 -0
  168. package/src/features/aggregation/aggregationFns.ts +336 -0
  169. package/src/features/column-filtering/columnFilteringFeature.types.ts +61 -1
  170. package/src/features/column-filtering/columnFilteringFeature.utils.ts +33 -19
  171. package/src/features/column-filtering/createFilteredRowModel.ts +13 -3
  172. package/src/features/column-filtering/filterFns.ts +533 -0
  173. package/src/features/column-grouping/columnGroupingFeature.ts +1 -20
  174. package/src/features/column-grouping/columnGroupingFeature.types.ts +4 -86
  175. package/src/features/column-grouping/columnGroupingFeature.utils.ts +1 -88
  176. package/src/features/column-grouping/createGroupedRowModel.ts +32 -38
  177. package/src/features/global-filtering/globalFilteringFeature.utils.ts +9 -1
  178. package/src/features/row-sorting/createSortedRowModel.ts +6 -2
  179. package/src/features/row-sorting/rowSortingFeature.types.ts +54 -2
  180. package/src/features/row-sorting/rowSortingFeature.utils.ts +46 -14
  181. package/src/{fns → features/row-sorting}/sortFns.ts +95 -81
  182. package/src/features/stockFeatures.ts +3 -0
  183. package/src/helpers/tableFeatures.ts +5 -4
  184. package/src/index.ts +7 -8
  185. package/src/static-functions.ts +1 -0
  186. package/src/types/Cell.ts +2 -0
  187. package/src/types/Column.ts +3 -1
  188. package/src/types/ColumnDef.ts +6 -3
  189. package/src/types/Row.ts +2 -0
  190. package/src/types/RowModelFns.ts +3 -3
  191. package/src/types/TableFeatures.ts +19 -11
  192. package/src/types/TableOptions.ts +5 -1
  193. package/src/types/type-utils.ts +8 -0
  194. package/src/worker/initTableWorker.ts +1 -1
  195. package/dist/fns/aggregationFns.cjs +0 -163
  196. package/dist/fns/aggregationFns.cjs.map +0 -1
  197. package/dist/fns/aggregationFns.d.cts +0 -85
  198. package/dist/fns/aggregationFns.d.ts +0 -85
  199. package/dist/fns/aggregationFns.js +0 -153
  200. package/dist/fns/aggregationFns.js.map +0 -1
  201. package/dist/fns/filterFns.cjs +0 -242
  202. package/dist/fns/filterFns.cjs.map +0 -1
  203. package/dist/fns/filterFns.d.cts +0 -178
  204. package/dist/fns/filterFns.d.ts +0 -178
  205. package/dist/fns/filterFns.js +0 -226
  206. package/dist/fns/filterFns.js.map +0 -1
  207. package/dist/fns/sortFns.cjs.map +0 -1
  208. package/dist/fns/sortFns.d.cts +0 -65
  209. package/dist/fns/sortFns.d.ts +0 -65
  210. package/dist/fns/sortFns.js.map +0 -1
  211. package/src/fns/aggregationFns.ts +0 -245
  212. 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 '../../fns/filterFns'
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`, arrays use `arrIncludes`, and unknown values fall back
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
- if (typeof value === 'string') {
51
- return filterFns?.includesString
52
- }
54
+ let filterFnName: string
53
55
 
54
- if (typeof value === 'number') {
55
- return filterFns?.inNumberRange
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
- if (typeof value === 'boolean') {
59
- return filterFns?.equals
60
- }
72
+ const filterFn = filterFns?.[filterFnName]
61
73
 
62
- if (Array.isArray(value)) {
63
- return filterFns?.arrIncludes
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 filterFns?.weakEquals
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 (process.env.NODE_ENV === 'development' && !filterFn) {
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
- `Could not find a valid 'column.filterFn' for column with the ID: ${column.id}.`,
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 `features` option:
26
- * `tableFeatures({ columnFilteringFeature, filteredRowModel: createFilteredRowModel(), filterFns })`.
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,