@tanstack/table-core 9.0.0-beta.45 → 9.0.0-beta.47

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 (116) hide show
  1. package/dist/features/column-filtering/columnFilteringFeature.types.d.cts +43 -3
  2. package/dist/features/column-filtering/columnFilteringFeature.types.d.ts +43 -3
  3. package/dist/features/column-filtering/columnFilteringFeature.utils.cjs +18 -9
  4. package/dist/features/column-filtering/columnFilteringFeature.utils.cjs.map +1 -1
  5. package/dist/features/column-filtering/columnFilteringFeature.utils.d.cts +6 -2
  6. package/dist/features/column-filtering/columnFilteringFeature.utils.d.ts +6 -2
  7. package/dist/features/column-filtering/columnFilteringFeature.utils.js +18 -9
  8. package/dist/features/column-filtering/columnFilteringFeature.utils.js.map +1 -1
  9. package/dist/features/column-filtering/createFilteredRowModel.cjs +7 -2
  10. package/dist/features/column-filtering/createFilteredRowModel.cjs.map +1 -1
  11. package/dist/features/column-filtering/createFilteredRowModel.d.cts +6 -2
  12. package/dist/features/column-filtering/createFilteredRowModel.d.ts +6 -2
  13. package/dist/features/column-filtering/createFilteredRowModel.js +7 -2
  14. package/dist/features/column-filtering/createFilteredRowModel.js.map +1 -1
  15. package/dist/features/column-grouping/columnGroupingFeature.types.d.cts +41 -3
  16. package/dist/features/column-grouping/columnGroupingFeature.types.d.ts +41 -3
  17. package/dist/features/column-grouping/columnGroupingFeature.utils.cjs +17 -3
  18. package/dist/features/column-grouping/columnGroupingFeature.utils.cjs.map +1 -1
  19. package/dist/features/column-grouping/columnGroupingFeature.utils.d.cts +5 -0
  20. package/dist/features/column-grouping/columnGroupingFeature.utils.d.ts +5 -0
  21. package/dist/features/column-grouping/columnGroupingFeature.utils.js +17 -3
  22. package/dist/features/column-grouping/columnGroupingFeature.utils.js.map +1 -1
  23. package/dist/features/column-grouping/createGroupedRowModel.cjs +6 -3
  24. package/dist/features/column-grouping/createGroupedRowModel.cjs.map +1 -1
  25. package/dist/features/column-grouping/createGroupedRowModel.d.cts +6 -3
  26. package/dist/features/column-grouping/createGroupedRowModel.d.ts +6 -3
  27. package/dist/features/column-grouping/createGroupedRowModel.js +6 -3
  28. package/dist/features/column-grouping/createGroupedRowModel.js.map +1 -1
  29. package/dist/features/global-filtering/globalFilteringFeature.utils.cjs +3 -1
  30. package/dist/features/global-filtering/globalFilteringFeature.utils.cjs.map +1 -1
  31. package/dist/features/global-filtering/globalFilteringFeature.utils.d.cts +2 -6
  32. package/dist/features/global-filtering/globalFilteringFeature.utils.d.ts +2 -6
  33. package/dist/features/global-filtering/globalFilteringFeature.utils.js +3 -1
  34. package/dist/features/global-filtering/globalFilteringFeature.utils.js.map +1 -1
  35. package/dist/features/row-sorting/createSortedRowModel.cjs +6 -2
  36. package/dist/features/row-sorting/createSortedRowModel.cjs.map +1 -1
  37. package/dist/features/row-sorting/createSortedRowModel.d.cts +6 -2
  38. package/dist/features/row-sorting/createSortedRowModel.d.ts +6 -2
  39. package/dist/features/row-sorting/createSortedRowModel.js +6 -2
  40. package/dist/features/row-sorting/createSortedRowModel.js.map +1 -1
  41. package/dist/features/row-sorting/rowSortingFeature.types.d.cts +31 -2
  42. package/dist/features/row-sorting/rowSortingFeature.types.d.ts +31 -2
  43. package/dist/features/row-sorting/rowSortingFeature.utils.cjs +19 -4
  44. package/dist/features/row-sorting/rowSortingFeature.utils.cjs.map +1 -1
  45. package/dist/features/row-sorting/rowSortingFeature.utils.js +19 -4
  46. package/dist/features/row-sorting/rowSortingFeature.utils.js.map +1 -1
  47. package/dist/fns/aggregationFns.cjs +128 -57
  48. package/dist/fns/aggregationFns.cjs.map +1 -1
  49. package/dist/fns/aggregationFns.d.cts +72 -18
  50. package/dist/fns/aggregationFns.d.ts +72 -18
  51. package/dist/fns/aggregationFns.js +126 -58
  52. package/dist/fns/aggregationFns.js.map +1 -1
  53. package/dist/fns/filterFns.cjs +254 -97
  54. package/dist/fns/filterFns.cjs.map +1 -1
  55. package/dist/fns/filterFns.d.cts +126 -94
  56. package/dist/fns/filterFns.d.ts +126 -94
  57. package/dist/fns/filterFns.js +247 -98
  58. package/dist/fns/filterFns.js.map +1 -1
  59. package/dist/fns/sortFns.cjs +68 -21
  60. package/dist/fns/sortFns.cjs.map +1 -1
  61. package/dist/fns/sortFns.d.cts +48 -15
  62. package/dist/fns/sortFns.d.ts +48 -15
  63. package/dist/fns/sortFns.js +68 -22
  64. package/dist/fns/sortFns.js.map +1 -1
  65. package/dist/helpers/tableFeatures.cjs +5 -4
  66. package/dist/helpers/tableFeatures.cjs.map +1 -1
  67. package/dist/helpers/tableFeatures.d.cts +5 -4
  68. package/dist/helpers/tableFeatures.d.ts +5 -4
  69. package/dist/helpers/tableFeatures.js +5 -4
  70. package/dist/helpers/tableFeatures.js.map +1 -1
  71. package/dist/index.cjs +12 -0
  72. package/dist/index.d.cts +8 -8
  73. package/dist/index.d.ts +8 -8
  74. package/dist/index.js +4 -4
  75. package/dist/types/TableFeatures.d.cts +15 -7
  76. package/dist/types/TableFeatures.d.ts +15 -7
  77. package/dist/types/type-utils.d.cts +8 -1
  78. package/dist/types/type-utils.d.ts +8 -1
  79. package/package.json +1 -1
  80. package/skills/api-not-found/SKILL.md +1 -1
  81. package/skills/client-vs-server/SKILL.md +1 -1
  82. package/skills/column-faceting/SKILL.md +11 -5
  83. package/skills/column-filtering/SKILL.md +8 -3
  84. package/skills/column-ordering/SKILL.md +1 -1
  85. package/skills/column-pinning/SKILL.md +1 -1
  86. package/skills/column-resizing/SKILL.md +1 -1
  87. package/skills/column-sizing/SKILL.md +1 -1
  88. package/skills/column-visibility/SKILL.md +1 -1
  89. package/skills/core/SKILL.md +1 -1
  90. package/skills/custom-features/SKILL.md +1 -1
  91. package/skills/expanding/SKILL.md +1 -1
  92. package/skills/global-filtering/SKILL.md +3 -3
  93. package/skills/grouping/SKILL.md +8 -3
  94. package/skills/migrate-v8-to-v9/SKILL.md +7 -7
  95. package/skills/pagination/SKILL.md +1 -1
  96. package/skills/row-pinning/SKILL.md +1 -1
  97. package/skills/row-selection/SKILL.md +1 -1
  98. package/skills/sorting/SKILL.md +9 -3
  99. package/skills/table-features/SKILL.md +16 -13
  100. package/skills/typescript/SKILL.md +1 -1
  101. package/src/features/column-filtering/columnFilteringFeature.types.ts +60 -0
  102. package/src/features/column-filtering/columnFilteringFeature.utils.ts +33 -19
  103. package/src/features/column-filtering/createFilteredRowModel.ts +13 -3
  104. package/src/features/column-grouping/columnGroupingFeature.types.ts +63 -8
  105. package/src/features/column-grouping/columnGroupingFeature.utils.ts +43 -9
  106. package/src/features/column-grouping/createGroupedRowModel.ts +6 -3
  107. package/src/features/global-filtering/globalFilteringFeature.utils.ts +8 -0
  108. package/src/features/row-sorting/createSortedRowModel.ts +6 -2
  109. package/src/features/row-sorting/rowSortingFeature.types.ts +53 -1
  110. package/src/features/row-sorting/rowSortingFeature.utils.ts +45 -13
  111. package/src/fns/aggregationFns.ts +204 -146
  112. package/src/fns/filterFns.ts +361 -280
  113. package/src/fns/sortFns.ts +95 -78
  114. package/src/helpers/tableFeatures.ts +5 -4
  115. package/src/types/TableFeatures.ts +15 -7
  116. package/src/types/type-utils.ts +8 -0
@@ -1,32 +1,72 @@
1
1
 
2
2
  //#region src/fns/filterFns.ts
3
3
  /**
4
+ * Builds a `FilterFn` from a value-level comparator plus optional resolvers.
5
+ *
6
+ * The `filter` comparator receives the row's data value (already passed
7
+ * through `resolveDataValue` when one is defined) and the filter value
8
+ * (already passed through `resolveFilterValue` by the table). Keeping
9
+ * normalization in the resolvers means a variant of an existing filter
10
+ * function only has to swap the resolvers, not re-implement the comparison.
11
+ *
12
+ * The definition is attached to the returned function, so a variant can be
13
+ * created by spreading a built-in filter function and overriding what differs:
14
+ *
15
+ * ```ts
16
+ * const normalize = (value: unknown) =>
17
+ * String(value ?? '')
18
+ * .toLowerCase()
19
+ * .normalize('NFD')
20
+ * .replace(/\p{Diacritic}/gu, '')
21
+ *
22
+ * const includesStringIgnoreDiacritics = constructFilterFn({
23
+ * ...filterFn_includesString,
24
+ * resolveFilterValue: normalize,
25
+ * resolveDataValue: normalize,
26
+ * })
27
+ * ```
28
+ *
29
+ * Note: the table applies `resolveFilterValue` once per filter before any rows
30
+ * are tested. When calling a filter function directly (outside of a table),
31
+ * apply it yourself: `fn(row, columnId, fn.resolveFilterValue?.(value) ?? value)`.
32
+ */
33
+ function constructFilterFn(def) {
34
+ const filterFn = Object.assign((row, columnId, filterValue, addMeta) => {
35
+ const rawValue = row.getValue(columnId);
36
+ const dataValue = filterFn.resolveDataValue ? filterFn.resolveDataValue(rawValue) : rawValue;
37
+ return filterFn.filter(dataValue, filterValue, row, columnId, addMeta);
38
+ }, def);
39
+ return filterFn;
40
+ }
41
+ /**
4
42
  * Keeps rows whose column value is strictly equal to the filter value.
5
43
  *
6
44
  * Uses JavaScript `===` comparison and auto-removes empty filter values.
7
45
  */
8
- const filterFn_equals = Object.assign((row, columnId, filterValue) => {
9
- return row.getValue(columnId) === filterValue;
10
- }, { autoRemove: (val) => testFalsy(val) });
46
+ const filterFn_equals = constructFilterFn({
47
+ filter: (dataValue, filterValue) => dataValue === filterValue,
48
+ autoRemove: (val) => testFalsy(val)
49
+ });
11
50
  /**
12
51
  * Keeps rows whose column value is loosely equal to the filter value.
13
52
  *
14
53
  * Uses JavaScript `==` comparison and auto-removes empty filter values. This is
15
54
  * useful for matching string input against numeric row values.
16
55
  */
17
- const filterFn_weakEquals = Object.assign((row, columnId, filterValue) => {
18
- return row.getValue(columnId) == filterValue;
19
- }, { autoRemove: (val) => testFalsy(val) });
56
+ const filterFn_weakEquals = constructFilterFn({
57
+ filter: (dataValue, filterValue) => dataValue == filterValue,
58
+ autoRemove: (val) => testFalsy(val)
59
+ });
20
60
  /**
21
61
  * Keeps rows whose stringified column value includes the filter text.
22
62
  *
23
63
  * Matching is case-sensitive and empty filter values are auto-removed.
24
64
  */
25
- const filterFn_includesStringSensitive = Object.assign((row, columnId, filterValue) => {
26
- return Boolean(row.getValue(columnId)?.toString().includes(String(filterValue)));
27
- }, {
65
+ const filterFn_includesStringSensitive = constructFilterFn({
66
+ filter: (dataValue, filterValue) => Boolean(dataValue?.includes(filterValue)),
28
67
  autoRemove: (val) => testFalsy(val),
29
- resolveFilterValue: (val) => String(val)
68
+ resolveFilterValue: (val) => String(val),
69
+ resolveDataValue: (val) => val == null ? void 0 : String(val)
30
70
  });
31
71
  /**
32
72
  * Keeps rows whose stringified column value includes the filter text.
@@ -34,11 +74,11 @@ const filterFn_includesStringSensitive = Object.assign((row, columnId, filterVal
34
74
  * Both values are lowercased before comparison, and empty filter values are
35
75
  * auto-removed.
36
76
  */
37
- const filterFn_includesString = Object.assign((row, columnId, filterValue) => {
38
- return Boolean(row.getValue(columnId)?.toString().toLowerCase().includes(String(filterValue).toLowerCase()));
39
- }, {
77
+ const filterFn_includesString = constructFilterFn({
78
+ filter: (dataValue, filterValue) => Boolean(dataValue?.includes(filterValue)),
40
79
  autoRemove: (val) => testFalsy(val),
41
- resolveFilterValue: (val) => String(val).toLowerCase()
80
+ resolveFilterValue: (val) => String(val).toLowerCase(),
81
+ resolveDataValue: (val) => val == null ? void 0 : String(val).toLowerCase()
42
82
  });
43
83
  /**
44
84
  * Keeps rows whose stringified column value equals the filter text.
@@ -46,22 +86,68 @@ const filterFn_includesString = Object.assign((row, columnId, filterValue) => {
46
86
  * Both values are lowercased before comparison, and empty filter values are
47
87
  * auto-removed.
48
88
  */
49
- const filterFn_equalsString = Object.assign((row, columnId, filterValue) => {
50
- return row.getValue(columnId)?.toString().toLowerCase() === String(filterValue).toLowerCase();
51
- }, {
89
+ const filterFn_equalsString = constructFilterFn({
90
+ filter: (dataValue, filterValue) => dataValue === filterValue,
52
91
  autoRemove: (val) => testFalsy(val),
53
- resolveFilterValue: (val) => String(val).toLowerCase()
92
+ resolveFilterValue: (val) => String(val).toLowerCase(),
93
+ resolveDataValue: (val) => val == null ? void 0 : String(val).toLowerCase()
54
94
  });
55
95
  /**
56
96
  * Keeps rows whose stringified column value exactly equals the filter text.
57
97
  *
58
98
  * Matching is case-sensitive and empty filter values are auto-removed.
59
99
  */
60
- const filterFn_equalsStringSensitive = Object.assign((row, columnId, filterValue) => {
61
- return row.getValue(columnId)?.toString() === String(filterValue);
62
- }, {
100
+ const filterFn_equalsStringSensitive = constructFilterFn({
101
+ filter: (dataValue, filterValue) => dataValue === filterValue,
102
+ autoRemove: (val) => testFalsy(val),
103
+ resolveFilterValue: (val) => String(val),
104
+ resolveDataValue: (val) => val == null ? void 0 : String(val)
105
+ });
106
+ /**
107
+ * Keeps rows whose stringified column value starts with the filter text.
108
+ *
109
+ * Both values are lowercased before comparison, and empty filter values are
110
+ * auto-removed.
111
+ */
112
+ const filterFn_startsWith = constructFilterFn({
113
+ filter: (dataValue, filterValue) => Boolean(dataValue?.startsWith(filterValue)),
114
+ autoRemove: (val) => testFalsy(val),
115
+ resolveFilterValue: (val) => String(val).toLowerCase(),
116
+ resolveDataValue: (val) => val == null ? void 0 : String(val).toLowerCase()
117
+ });
118
+ /**
119
+ * Keeps rows whose stringified column value ends with the filter text.
120
+ *
121
+ * Both values are lowercased before comparison, and empty filter values are
122
+ * auto-removed.
123
+ */
124
+ const filterFn_endsWith = constructFilterFn({
125
+ filter: (dataValue, filterValue) => Boolean(dataValue?.endsWith(filterValue)),
63
126
  autoRemove: (val) => testFalsy(val),
64
- resolveFilterValue: (val) => String(val)
127
+ resolveFilterValue: (val) => String(val).toLowerCase(),
128
+ resolveDataValue: (val) => val == null ? void 0 : String(val).toLowerCase()
129
+ });
130
+ /**
131
+ * Keeps rows whose column value is empty.
132
+ *
133
+ * A value is empty when it is nullish or stringifies to whitespace only. The
134
+ * filter value acts as an on/off flag: `false` and blank values are
135
+ * auto-removed.
136
+ */
137
+ const filterFn_empty = constructFilterFn({
138
+ filter: (dataValue) => testValueEmpty(dataValue),
139
+ autoRemove: (val) => testFalsy(val) || val === false
140
+ });
141
+ /**
142
+ * Keeps rows whose column value is not empty.
143
+ *
144
+ * A value is empty when it is nullish or stringifies to whitespace only. The
145
+ * filter value acts as an on/off flag: `false` and blank values are
146
+ * auto-removed.
147
+ */
148
+ const filterFn_notEmpty = constructFilterFn({
149
+ filter: (dataValue) => !testValueEmpty(dataValue),
150
+ autoRemove: (val) => testFalsy(val) || val === false
65
151
  });
66
152
  /**
67
153
  * Keeps rows whose value is greater than the filter value.
@@ -69,86 +155,66 @@ const filterFn_equalsStringSensitive = Object.assign((row, columnId, filterValue
69
155
  * Numeric values are compared numerically when both sides can be coerced to
70
156
  * numbers; otherwise normalized strings are compared.
71
157
  */
72
- const filterFn_greaterThan = Object.assign((row, columnId, filterValue) => {
73
- const rowValue = row.getValue(columnId);
74
- const numericRowValue = rowValue === null || rowValue === void 0 ? 0 : +rowValue;
75
- const numericFilterValue = Number(filterValue);
76
- if (!isNaN(numericFilterValue) && !isNaN(numericRowValue)) return numericRowValue > numericFilterValue;
77
- return (rowValue ?? "").toString().toLowerCase().trim() > String(filterValue).toLowerCase().trim();
78
- }, { autoRemove: (val) => testFalsy(val) });
158
+ const filterFn_greaterThan = constructFilterFn({
159
+ filter: (dataValue, filterValue) => compareGreaterThan(dataValue, filterValue),
160
+ autoRemove: (val) => testFalsy(val)
161
+ });
79
162
  /**
80
163
  * Keeps rows whose value is greater than or equal to the filter value.
81
164
  *
82
- * Delegates to the built-in greater-than and equality comparisons.
165
+ * Delegates to the built-in greater-than and strict-equality comparisons.
83
166
  */
84
- const filterFn_greaterThanOrEqualTo = Object.assign((row, columnId, filterValue) => {
85
- return filterFn_greaterThan(row, columnId, filterValue) || filterFn_equals(row, columnId, filterValue);
86
- }, { autoRemove: (val) => testFalsy(val) });
167
+ const filterFn_greaterThanOrEqualTo = constructFilterFn({
168
+ filter: (dataValue, filterValue) => compareGreaterThanOrEqualTo(dataValue, filterValue),
169
+ autoRemove: (val) => testFalsy(val)
170
+ });
87
171
  /**
88
172
  * Keeps rows whose value is less than the filter value.
89
173
  *
90
174
  * This is implemented as the inverse of greater-than-or-equal comparison.
91
175
  */
92
- const filterFn_lessThan = Object.assign((row, columnId, filterValue) => {
93
- return !filterFn_greaterThanOrEqualTo(row, columnId, filterValue);
94
- }, { autoRemove: (val) => testFalsy(val) });
176
+ const filterFn_lessThan = constructFilterFn({
177
+ filter: (dataValue, filterValue) => !compareGreaterThanOrEqualTo(dataValue, filterValue),
178
+ autoRemove: (val) => testFalsy(val)
179
+ });
95
180
  /**
96
181
  * Keeps rows whose value is less than or equal to the filter value.
97
182
  *
98
183
  * This is implemented as the inverse of greater-than comparison.
99
184
  */
100
- const filterFn_lessThanOrEqualTo = Object.assign((row, columnId, filterValue) => {
101
- return !filterFn_greaterThan(row, columnId, filterValue);
102
- }, { autoRemove: (val) => testFalsy(val) });
185
+ const filterFn_lessThanOrEqualTo = constructFilterFn({
186
+ filter: (dataValue, filterValue) => !compareGreaterThan(dataValue, filterValue),
187
+ autoRemove: (val) => testFalsy(val)
188
+ });
103
189
  /**
104
190
  * Keeps rows whose value falls between an exclusive min/max pair.
105
191
  *
106
192
  * Blank range endpoints are treated as open-ended.
107
193
  */
108
- const filterFn_between = Object.assign((row, columnId, filterValues) => {
109
- const min = filterValues[0];
110
- if (min !== "" && min !== void 0) {
111
- if (!filterFn_greaterThan(row, columnId, min)) return false;
112
- }
113
- const max = filterValues[1];
114
- if (max === "" || max === void 0) return true;
115
- if (min !== "" && min !== void 0) {
116
- const numericMin = Number(min);
117
- const numericMax = Number(max);
118
- if (!isNaN(numericMin) && !isNaN(numericMax) && numericMin > numericMax) return true;
119
- }
120
- return filterFn_lessThan(row, columnId, max);
121
- }, { autoRemove: (val) => testFalsy(val) || testFalsy(val[0]) && testFalsy(val[1]) });
194
+ const filterFn_between = constructFilterFn({
195
+ filter: (dataValue, filterValues) => compareBetween(dataValue, filterValues, false),
196
+ autoRemove: (val) => testFalsy(val) || Array.isArray(val) && testFalsy(val[0]) && testFalsy(val[1])
197
+ });
122
198
  /**
123
199
  * Keeps rows whose value falls between an inclusive min/max pair.
124
200
  *
125
201
  * Blank range endpoints are treated as open-ended.
126
202
  */
127
- const filterFn_betweenInclusive = Object.assign((row, columnId, filterValues) => {
128
- const min = filterValues[0];
129
- if (min !== "" && min !== void 0) {
130
- if (!filterFn_greaterThanOrEqualTo(row, columnId, min)) return false;
131
- }
132
- const max = filterValues[1];
133
- if (max === "" || max === void 0) return true;
134
- if (min !== "" && min !== void 0) {
135
- const numericMin = Number(min);
136
- const numericMax = Number(max);
137
- if (!isNaN(numericMin) && !isNaN(numericMax) && numericMin > numericMax) return true;
138
- }
139
- return filterFn_lessThanOrEqualTo(row, columnId, max);
140
- }, { autoRemove: (val) => testFalsy(val) || testFalsy(val[0]) && testFalsy(val[1]) });
203
+ const filterFn_betweenInclusive = constructFilterFn({
204
+ filter: (dataValue, filterValues) => compareBetween(dataValue, filterValues, true),
205
+ autoRemove: (val) => testFalsy(val) || Array.isArray(val) && testFalsy(val[0]) && testFalsy(val[1])
206
+ });
141
207
  /**
142
208
  * Keeps rows whose numeric value is inside an inclusive `[min, max]` range.
143
209
  *
144
210
  * Filter values are normalized so blank endpoints become open-ended and
145
211
  * reversed endpoints are swapped.
146
212
  */
147
- const filterFn_inNumberRange = Object.assign((row, columnId, filterValue) => {
148
- const [min, max] = filterValue;
149
- const rowValue = row.getValue(columnId);
150
- return rowValue >= min && rowValue <= max;
151
- }, {
213
+ const filterFn_inNumberRange = constructFilterFn({
214
+ filter: (dataValue, filterValue) => {
215
+ const [min, max] = filterValue;
216
+ return dataValue >= min && dataValue <= max;
217
+ },
152
218
  resolveFilterValue: (val) => {
153
219
  const [unsafeMin, unsafeMax] = val;
154
220
  const parsedMin = typeof unsafeMin !== "number" ? parseFloat(unsafeMin) : unsafeMin;
@@ -162,47 +228,91 @@ const filterFn_inNumberRange = Object.assign((row, columnId, filterValue) => {
162
228
  }
163
229
  return [min, max];
164
230
  },
165
- autoRemove: (val) => testFalsy(val) || testFalsy(val[0]) && testFalsy(val[1])
231
+ autoRemove: (val) => testFalsy(val) || Array.isArray(val) && testFalsy(val[0]) && testFalsy(val[1])
232
+ });
233
+ /**
234
+ * Keeps rows whose date value is inside an inclusive `[min, max]` date range.
235
+ *
236
+ * Row values and range endpoints may be `Date` objects, timestamps, or
237
+ * parseable date strings. Blank or invalid endpoints become open-ended and
238
+ * reversed endpoints are swapped. Rows without a valid date never match.
239
+ */
240
+ const filterFn_inDateRange = constructFilterFn({
241
+ filter: (dataValue, filterValue) => {
242
+ const [min, max] = filterValue;
243
+ return dataValue >= min && dataValue <= max;
244
+ },
245
+ resolveFilterValue: (val) => {
246
+ const [unsafeMin, unsafeMax] = val;
247
+ const parsedMin = toDateTimestamp(unsafeMin);
248
+ const parsedMax = toDateTimestamp(unsafeMax);
249
+ let min = Number.isNaN(parsedMin) ? -Infinity : parsedMin;
250
+ let max = Number.isNaN(parsedMax) ? Infinity : parsedMax;
251
+ if (min > max) {
252
+ const temp = min;
253
+ min = max;
254
+ max = temp;
255
+ }
256
+ return [min, max];
257
+ },
258
+ resolveDataValue: (val) => toDateTimestamp(val),
259
+ autoRemove: (val) => testFalsy(val) || Array.isArray(val) && testFalsy(val[0]) && testFalsy(val[1])
166
260
  });
167
261
  /**
168
262
  * Keeps rows whose scalar column value equals at least one filter value.
169
263
  */
170
- const filterFn_arrHas = Object.assign((row, columnId, filterValue) => {
171
- const value = row.getValue(columnId);
172
- for (let i = 0; i < filterValue.length; i++) if (value === filterValue[i]) return true;
173
- return false;
174
- }, { autoRemove: (val) => testFalsy(val) || !val?.length });
264
+ const filterFn_arrHas = constructFilterFn({
265
+ filter: (dataValue, filterValue) => {
266
+ for (let i = 0; i < filterValue.length; i++) if (dataValue === filterValue[i]) return true;
267
+ return false;
268
+ },
269
+ autoRemove: (val) => testFalsy(val) || !val?.length
270
+ });
175
271
  /**
176
272
  * Keeps rows whose array or string column value includes at least one filter value.
177
273
  */
178
- const filterFn_arrIncludes = Object.assign((row, columnId, filterValue) => {
179
- const value = row.getValue(columnId);
180
- if (typeof value !== "string" && !Array.isArray(value)) return false;
181
- for (let i = 0; i < filterValue.length; i++) if (value.includes(filterValue[i])) return true;
182
- return false;
183
- }, { autoRemove: (val) => testFalsy(val) || !val?.length });
274
+ const filterFn_arrIncludes = constructFilterFn({
275
+ filter: (dataValue, filterValue) => {
276
+ if (typeof dataValue !== "string" && !Array.isArray(dataValue)) return false;
277
+ for (let i = 0; i < filterValue.length; i++) if (dataValue.includes(filterValue[i])) return true;
278
+ return false;
279
+ },
280
+ autoRemove: (val) => testFalsy(val) || !val?.length
281
+ });
184
282
  /**
185
283
  * Keeps rows whose array column value includes every filter value.
186
284
  */
187
- const filterFn_arrIncludesAll = Object.assign((row, columnId, filterValue) => {
188
- const value = row.getValue(columnId);
189
- if (!Array.isArray(value)) return false;
190
- for (let i = 0; i < filterValue.length; i++) if (!value.includes(filterValue[i])) return false;
191
- return true;
192
- }, { autoRemove: (val) => testFalsy(val) || !val?.length });
285
+ const filterFn_arrIncludesAll = constructFilterFn({
286
+ filter: (dataValue, filterValue) => {
287
+ if (!Array.isArray(dataValue)) return false;
288
+ for (let i = 0; i < filterValue.length; i++) if (!dataValue.includes(filterValue[i])) return false;
289
+ return true;
290
+ },
291
+ autoRemove: (val) => testFalsy(val) || !val?.length
292
+ });
193
293
  /**
194
294
  * Keeps rows whose array column value includes at least one filter value.
195
295
  */
196
- const filterFn_arrIncludesSome = Object.assign((row, columnId, filterValue) => {
197
- const value = row.getValue(columnId);
198
- if (!Array.isArray(value)) return false;
199
- for (let i = 0; i < filterValue.length; i++) if (value.includes(filterValue[i])) return true;
200
- return false;
201
- }, { autoRemove: (val) => testFalsy(val) || !val?.length });
296
+ const filterFn_arrIncludesSome = constructFilterFn({
297
+ filter: (dataValue, filterValue) => {
298
+ if (!Array.isArray(dataValue)) return false;
299
+ for (let i = 0; i < filterValue.length; i++) if (dataValue.includes(filterValue[i])) return true;
300
+ return false;
301
+ },
302
+ autoRemove: (val) => testFalsy(val) || !val?.length
303
+ });
202
304
  /**
203
305
  * The built-in filter function registry.
204
306
  *
205
- * Pass this object to filtered row model creation or extend it with custom filter functions.
307
+ * Registering this full object opts out of tree-shaking: every built-in
308
+ * filter function ends up in your bundle. Prefer importing the `filterFn_*`
309
+ * functions you actually use and registering just those in the `filterFns`
310
+ * slot, or passing them directly to the `filterFn` column option.
311
+ *
312
+ * @deprecated Import individual `filterFn_*` functions instead for a smaller
313
+ * bundle. This export still works and is not going away in v9, but built-in
314
+ * name resolution (including `filterFn: 'auto'`) only finds functions you
315
+ * register yourself.
206
316
  */
207
317
  const filterFns = {
208
318
  arrIncludes: filterFn_arrIncludes,
@@ -211,32 +321,79 @@ const filterFns = {
211
321
  arrIncludesSome: filterFn_arrIncludesSome,
212
322
  between: filterFn_between,
213
323
  betweenInclusive: filterFn_betweenInclusive,
324
+ empty: filterFn_empty,
325
+ endsWith: filterFn_endsWith,
214
326
  equals: filterFn_equals,
215
327
  equalsString: filterFn_equalsString,
328
+ equalsStringSensitive: filterFn_equalsStringSensitive,
329
+ inDateRange: filterFn_inDateRange,
216
330
  inNumberRange: filterFn_inNumberRange,
217
331
  includesString: filterFn_includesString,
218
332
  includesStringSensitive: filterFn_includesStringSensitive,
333
+ notEmpty: filterFn_notEmpty,
334
+ startsWith: filterFn_startsWith,
219
335
  weakEquals: filterFn_weakEquals
220
336
  };
221
337
  function testFalsy(val) {
222
338
  return val === void 0 || val === null || val === "";
223
339
  }
340
+ function testValueEmpty(dataValue) {
341
+ return dataValue == null || String(dataValue).trim() === "";
342
+ }
343
+ function toDateTimestamp(value) {
344
+ if (value instanceof Date) return value.getTime();
345
+ if (typeof value === "number") return value;
346
+ if (value == null || value === "") return NaN;
347
+ return new Date(value).getTime();
348
+ }
349
+ function compareGreaterThan(dataValue, filterValue) {
350
+ const numericDataValue = dataValue == null ? 0 : +dataValue;
351
+ const numericFilterValue = Number(filterValue);
352
+ if (!isNaN(numericFilterValue) && !isNaN(numericDataValue)) return numericDataValue > numericFilterValue;
353
+ return String(dataValue ?? "").toLowerCase().trim() > String(filterValue).toLowerCase().trim();
354
+ }
355
+ function compareGreaterThanOrEqualTo(dataValue, filterValue) {
356
+ return dataValue === filterValue || compareGreaterThan(dataValue, filterValue);
357
+ }
358
+ function compareBetween(dataValue, filterValues, inclusive) {
359
+ const min = filterValues[0];
360
+ const hasMin = min !== "" && min !== void 0;
361
+ if (hasMin) {
362
+ if (!(inclusive ? compareGreaterThanOrEqualTo(dataValue, min) : compareGreaterThan(dataValue, min))) return false;
363
+ }
364
+ const max = filterValues[1];
365
+ if (max === "" || max === void 0) return true;
366
+ if (hasMin) {
367
+ const numericMin = Number(min);
368
+ const numericMax = Number(max);
369
+ if (!isNaN(numericMin) && !isNaN(numericMax) && numericMin > numericMax) return true;
370
+ }
371
+ return inclusive ? !compareGreaterThan(dataValue, max) : !compareGreaterThanOrEqualTo(dataValue, max);
372
+ }
224
373
 
225
374
  //#endregion
375
+ exports.constructFilterFn = constructFilterFn;
226
376
  exports.filterFn_arrHas = filterFn_arrHas;
227
377
  exports.filterFn_arrIncludes = filterFn_arrIncludes;
228
378
  exports.filterFn_arrIncludesAll = filterFn_arrIncludesAll;
229
379
  exports.filterFn_arrIncludesSome = filterFn_arrIncludesSome;
380
+ exports.filterFn_between = filterFn_between;
381
+ exports.filterFn_betweenInclusive = filterFn_betweenInclusive;
382
+ exports.filterFn_empty = filterFn_empty;
383
+ exports.filterFn_endsWith = filterFn_endsWith;
230
384
  exports.filterFn_equals = filterFn_equals;
231
385
  exports.filterFn_equalsString = filterFn_equalsString;
232
386
  exports.filterFn_equalsStringSensitive = filterFn_equalsStringSensitive;
233
387
  exports.filterFn_greaterThan = filterFn_greaterThan;
234
388
  exports.filterFn_greaterThanOrEqualTo = filterFn_greaterThanOrEqualTo;
389
+ exports.filterFn_inDateRange = filterFn_inDateRange;
235
390
  exports.filterFn_inNumberRange = filterFn_inNumberRange;
236
391
  exports.filterFn_includesString = filterFn_includesString;
237
392
  exports.filterFn_includesStringSensitive = filterFn_includesStringSensitive;
238
393
  exports.filterFn_lessThan = filterFn_lessThan;
239
394
  exports.filterFn_lessThanOrEqualTo = filterFn_lessThanOrEqualTo;
395
+ exports.filterFn_notEmpty = filterFn_notEmpty;
396
+ exports.filterFn_startsWith = filterFn_startsWith;
240
397
  exports.filterFn_weakEquals = filterFn_weakEquals;
241
398
  exports.filterFns = filterFns;
242
399
  //# sourceMappingURL=filterFns.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"filterFns.cjs","names":[],"sources":["../../src/fns/filterFns.ts"],"sourcesContent":["import type { RowData } from '../types/type-utils'\nimport type { TableFeatures } from '../types/TableFeatures'\nimport type { Row } from '../types/Row'\n\n// Basic filters\n\n/**\n * Keeps rows whose column value is strictly equal to the filter value.\n *\n * Uses JavaScript `===` comparison and auto-removes empty filter values.\n */\nexport const filterFn_equals = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return row.getValue(columnId) === filterValue\n },\n { autoRemove: (val: any) => testFalsy(val) },\n)\n\n/**\n * Keeps rows whose column value is loosely equal to the filter value.\n *\n * Uses JavaScript `==` comparison and auto-removes empty filter values. This is\n * useful for matching string input against numeric row values.\n */\nexport const filterFn_weakEquals = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return row.getValue(columnId) == filterValue\n },\n { autoRemove: (val: any) => testFalsy(val) },\n)\n\n// String filters\n\n/**\n * Keeps rows whose stringified column value includes the filter text.\n *\n * Matching is case-sensitive and empty filter values are auto-removed.\n */\nexport const filterFn_includesStringSensitive = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return Boolean(\n row.getValue(columnId)?.toString().includes(String(filterValue)),\n )\n },\n {\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val),\n },\n)\n\n/**\n * Keeps rows whose stringified column value includes the filter text.\n *\n * Both values are lowercased before comparison, and empty filter values are\n * auto-removed.\n */\nexport const filterFn_includesString = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return Boolean(\n row\n .getValue(columnId)\n ?.toString()\n .toLowerCase()\n .includes(String(filterValue).toLowerCase()),\n )\n },\n {\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val).toLowerCase(),\n },\n)\n\n/**\n * Keeps rows whose stringified column value equals the filter text.\n *\n * Both values are lowercased before comparison, and empty filter values are\n * auto-removed.\n */\nexport const filterFn_equalsString = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return (\n row.getValue(columnId)?.toString().toLowerCase() ===\n String(filterValue).toLowerCase()\n )\n },\n {\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val).toLowerCase(),\n },\n)\n\n/**\n * Keeps rows whose stringified column value exactly equals the filter text.\n *\n * Matching is case-sensitive and empty filter values are auto-removed.\n */\nexport const filterFn_equalsStringSensitive = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return row.getValue(columnId)?.toString() === String(filterValue)\n },\n {\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val),\n },\n)\n\n// Number filters\n\n/**\n * Keeps rows whose value is greater than the filter value.\n *\n * Numeric values are compared numerically when both sides can be coerced to\n * numbers; otherwise normalized strings are compared.\n */\nexport const filterFn_greaterThan = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n const rowValue = row.getValue(columnId)\n const numericRowValue =\n rowValue === null || rowValue === undefined ? 0 : +rowValue\n const numericFilterValue = Number(filterValue)\n\n if (!isNaN(numericFilterValue) && !isNaN(numericRowValue)) {\n return numericRowValue > numericFilterValue\n }\n\n const stringValue = (rowValue ?? '').toString().toLowerCase().trim()\n const stringFilterValue = String(filterValue).toLowerCase().trim()\n return stringValue > stringFilterValue\n },\n { autoRemove: (val: any) => testFalsy(val) },\n)\n\n/**\n * Keeps rows whose value is greater than or equal to the filter value.\n *\n * Delegates to the built-in greater-than and equality comparisons.\n */\nexport const filterFn_greaterThanOrEqualTo = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return (\n filterFn_greaterThan(row, columnId, filterValue) ||\n filterFn_equals(row, columnId, filterValue)\n )\n },\n { autoRemove: (val: any) => testFalsy(val) },\n)\n\n/**\n * Keeps rows whose value is less than the filter value.\n *\n * This is implemented as the inverse of greater-than-or-equal comparison.\n */\nexport const filterFn_lessThan = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return !filterFn_greaterThanOrEqualTo(row, columnId, filterValue)\n },\n { autoRemove: (val: any) => testFalsy(val) },\n)\n\n/**\n * Keeps rows whose value is less than or equal to the filter value.\n *\n * This is implemented as the inverse of greater-than comparison.\n */\nexport const filterFn_lessThanOrEqualTo = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return !filterFn_greaterThan(row, columnId, filterValue)\n },\n { autoRemove: (val: any) => testFalsy(val) },\n)\n\n// Range filters\n\n/**\n * Keeps rows whose value falls between an exclusive min/max pair.\n *\n * Blank range endpoints are treated as open-ended.\n */\nconst filterFn_between = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValues: [unknown, unknown],\n ): boolean => {\n const min = filterValues[0]\n if (min !== '' && min !== undefined) {\n if (!filterFn_greaterThan(row, columnId, min)) {\n return false\n }\n }\n\n const max = filterValues[1]\n if (max === '' || max === undefined) {\n return true\n }\n\n if (min !== '' && min !== undefined) {\n const numericMin = Number(min)\n const numericMax = Number(max)\n if (!isNaN(numericMin) && !isNaN(numericMax) && numericMin > numericMax) {\n return true\n }\n }\n\n return filterFn_lessThan(row, columnId, max)\n },\n {\n autoRemove: (val: any) =>\n testFalsy(val) || (testFalsy(val[0]) && testFalsy(val[1])),\n },\n)\n\n/**\n * Keeps rows whose value falls between an inclusive min/max pair.\n *\n * Blank range endpoints are treated as open-ended.\n */\nconst filterFn_betweenInclusive = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValues: [unknown, unknown],\n ): boolean => {\n const min = filterValues[0]\n if (min !== '' && min !== undefined) {\n if (!filterFn_greaterThanOrEqualTo(row, columnId, min)) {\n return false\n }\n }\n\n const max = filterValues[1]\n if (max === '' || max === undefined) {\n return true\n }\n\n if (min !== '' && min !== undefined) {\n const numericMin = Number(min)\n const numericMax = Number(max)\n if (!isNaN(numericMin) && !isNaN(numericMax) && numericMin > numericMax) {\n return true\n }\n }\n\n return filterFn_lessThanOrEqualTo(row, columnId, max)\n },\n {\n autoRemove: (val: any) =>\n testFalsy(val) || (testFalsy(val[0]) && testFalsy(val[1])),\n },\n)\n\n/**\n * Keeps rows whose numeric value is inside an inclusive `[min, max]` range.\n *\n * Filter values are normalized so blank endpoints become open-ended and\n * reversed endpoints are swapped.\n */\nexport const filterFn_inNumberRange = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: [number, number],\n ) => {\n const [min, max] = filterValue\n\n const rowValue: number = row.getValue(columnId)\n return rowValue >= min && rowValue <= max\n },\n {\n resolveFilterValue: (val: [any, any]) => {\n const [unsafeMin, unsafeMax] = val\n\n const parsedMin =\n typeof unsafeMin !== 'number' ? parseFloat(unsafeMin) : unsafeMin\n const parsedMax =\n typeof unsafeMax !== 'number' ? parseFloat(unsafeMax) : unsafeMax\n\n let min =\n unsafeMin === null || Number.isNaN(parsedMin) ? -Infinity : parsedMin\n let max =\n unsafeMax === null || Number.isNaN(parsedMax) ? Infinity : parsedMax\n\n if (min > max) {\n const temp = min\n min = max\n max = temp\n }\n\n return [min, max] as const\n },\n autoRemove: (val: any) =>\n testFalsy(val) || (testFalsy(val[0]) && testFalsy(val[1])),\n },\n)\n\n// Array filters\n\n/**\n * Keeps rows whose scalar column value equals at least one filter value.\n */\nexport const filterFn_arrHas = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: Array<unknown>,\n ) => {\n const value = row.getValue<unknown>(columnId)\n for (let i = 0; i < filterValue.length; i++) {\n if (value === filterValue[i]) {\n return true\n }\n }\n return false\n },\n { autoRemove: (val: any) => testFalsy(val) || !val?.length },\n)\n\n/**\n * Keeps rows whose array or string column value includes at least one filter value.\n */\nexport const filterFn_arrIncludes = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: Array<unknown>,\n ) => {\n const value = row.getValue<unknown>(columnId)\n if (typeof value !== 'string' && !Array.isArray(value)) {\n return false\n }\n\n for (let i = 0; i < filterValue.length; i++) {\n if (value.includes(filterValue[i] as any)) {\n return true\n }\n }\n return false\n },\n { autoRemove: (val: any) => testFalsy(val) || !val?.length },\n)\n\n/**\n * Keeps rows whose array column value includes every filter value.\n */\nexport const filterFn_arrIncludesAll = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: Array<unknown>,\n ) => {\n const value = row.getValue<Array<unknown>>(columnId)\n if (!Array.isArray(value)) return false\n for (let i = 0; i < filterValue.length; i++) {\n if (!value.includes(filterValue[i])) {\n return false\n }\n }\n return true\n },\n { autoRemove: (val: any) => testFalsy(val) || !val?.length },\n)\n\n/**\n * Keeps rows whose array column value includes at least one filter value.\n */\nexport const filterFn_arrIncludesSome = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: Array<unknown>,\n ) => {\n const value = row.getValue<Array<unknown>>(columnId)\n if (!Array.isArray(value)) return false\n for (let i = 0; i < filterValue.length; i++) {\n if (value.includes(filterValue[i])) {\n return true\n }\n }\n return false\n },\n { autoRemove: (val: any) => testFalsy(val) || !val?.length },\n)\n\n// Export\n\n/**\n * The built-in filter function registry.\n *\n * Pass this object to filtered row model creation or extend it with custom filter functions.\n */\nexport const filterFns = {\n arrIncludes: filterFn_arrIncludes,\n arrIncludesAll: filterFn_arrIncludesAll,\n arrHas: filterFn_arrHas,\n arrIncludesSome: filterFn_arrIncludesSome,\n between: filterFn_between,\n betweenInclusive: filterFn_betweenInclusive,\n equals: filterFn_equals,\n equalsString: filterFn_equalsString,\n inNumberRange: filterFn_inNumberRange,\n includesString: filterFn_includesString,\n includesStringSensitive: filterFn_includesStringSensitive,\n weakEquals: filterFn_weakEquals,\n}\n\nexport type BuiltInFilterFn = keyof typeof filterFns\n\n// Utils\n\nfunction testFalsy(val: any) {\n return val === undefined || val === null || val === ''\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"filterFns.cjs","names":[],"sources":["../../src/fns/filterFns.ts"],"sourcesContent":["import type {\n CreatedFilterFn,\n ExtractFilterMeta,\n FilterFnDef,\n} from '../features/column-filtering/columnFilteringFeature.types'\nimport type { RowData } from '../types/type-utils'\nimport type { TableFeatures } from '../types/TableFeatures'\nimport type { Row } from '../types/Row'\n\n/**\n * Builds a `FilterFn` from a value-level comparator plus optional resolvers.\n *\n * The `filter` comparator receives the row's data value (already passed\n * through `resolveDataValue` when one is defined) and the filter value\n * (already passed through `resolveFilterValue` by the table). Keeping\n * normalization in the resolvers means a variant of an existing filter\n * function only has to swap the resolvers, not re-implement the comparison.\n *\n * The definition is attached to the returned function, so a variant can be\n * created by spreading a built-in filter function and overriding what differs:\n *\n * ```ts\n * const normalize = (value: unknown) =>\n * String(value ?? '')\n * .toLowerCase()\n * .normalize('NFD')\n * .replace(/\\p{Diacritic}/gu, '')\n *\n * const includesStringIgnoreDiacritics = constructFilterFn({\n * ...filterFn_includesString,\n * resolveFilterValue: normalize,\n * resolveDataValue: normalize,\n * })\n * ```\n *\n * Note: the table applies `resolveFilterValue` once per filter before any rows\n * are tested. When calling a filter function directly (outside of a table),\n * apply it yourself: `fn(row, columnId, fn.resolveFilterValue?.(value) ?? value)`.\n */\nexport function constructFilterFn<\n TFeatures extends TableFeatures = any,\n TData extends RowData = any,\n>(def: FilterFnDef<TFeatures, TData>): CreatedFilterFn<TFeatures, TData> {\n const filterFn: CreatedFilterFn<TFeatures, TData> = Object.assign(\n <TRowFeatures extends TableFeatures, TRowData extends RowData>(\n row: Row<TRowFeatures, TRowData>,\n columnId: string,\n filterValue: any,\n addMeta?: (meta: ExtractFilterMeta<TRowFeatures>) => void,\n ): boolean => {\n const rawValue = row.getValue(columnId)\n const dataValue = filterFn.resolveDataValue\n ? filterFn.resolveDataValue(rawValue)\n : rawValue\n // The def's comparator is typed against the factory's TFeatures/TData;\n // the caller's row generics are erased at this boundary.\n return filterFn.filter(\n dataValue,\n filterValue,\n row as any,\n columnId,\n addMeta as any,\n )\n },\n def,\n )\n return filterFn\n}\n\n// Basic filters\n\n/**\n * Keeps rows whose column value is strictly equal to the filter value.\n *\n * Uses JavaScript `===` comparison and auto-removes empty filter values.\n */\nexport const filterFn_equals = constructFilterFn({\n filter: (dataValue, filterValue) => dataValue === filterValue,\n autoRemove: (val: any) => testFalsy(val),\n})\n\n/**\n * Keeps rows whose column value is loosely equal to the filter value.\n *\n * Uses JavaScript `==` comparison and auto-removes empty filter values. This is\n * useful for matching string input against numeric row values.\n */\nexport const filterFn_weakEquals = constructFilterFn({\n filter: (dataValue, filterValue) => dataValue == filterValue,\n autoRemove: (val: any) => testFalsy(val),\n})\n\n// String filters\n\n/**\n * Keeps rows whose stringified column value includes the filter text.\n *\n * Matching is case-sensitive and empty filter values are auto-removed.\n */\nexport const filterFn_includesStringSensitive = constructFilterFn({\n filter: (dataValue, filterValue) => Boolean(dataValue?.includes(filterValue)),\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val),\n resolveDataValue: (val: any) => (val == null ? undefined : String(val)),\n})\n\n/**\n * Keeps rows whose stringified column value includes the filter text.\n *\n * Both values are lowercased before comparison, and empty filter values are\n * auto-removed.\n */\nexport const filterFn_includesString = constructFilterFn({\n filter: (dataValue, filterValue) => Boolean(dataValue?.includes(filterValue)),\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val).toLowerCase(),\n resolveDataValue: (val: any) =>\n val == null ? undefined : String(val).toLowerCase(),\n})\n\n/**\n * Keeps rows whose stringified column value equals the filter text.\n *\n * Both values are lowercased before comparison, and empty filter values are\n * auto-removed.\n */\nexport const filterFn_equalsString = constructFilterFn({\n filter: (dataValue, filterValue) => dataValue === filterValue,\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val).toLowerCase(),\n resolveDataValue: (val: any) =>\n val == null ? undefined : String(val).toLowerCase(),\n})\n\n/**\n * Keeps rows whose stringified column value exactly equals the filter text.\n *\n * Matching is case-sensitive and empty filter values are auto-removed.\n */\nexport const filterFn_equalsStringSensitive = constructFilterFn({\n filter: (dataValue, filterValue) => dataValue === filterValue,\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val),\n resolveDataValue: (val: any) => (val == null ? undefined : String(val)),\n})\n\n/**\n * Keeps rows whose stringified column value starts with the filter text.\n *\n * Both values are lowercased before comparison, and empty filter values are\n * auto-removed.\n */\nexport const filterFn_startsWith = constructFilterFn({\n filter: (dataValue, filterValue) =>\n Boolean(dataValue?.startsWith(filterValue)),\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val).toLowerCase(),\n resolveDataValue: (val: any) =>\n val == null ? undefined : String(val).toLowerCase(),\n})\n\n/**\n * Keeps rows whose stringified column value ends with the filter text.\n *\n * Both values are lowercased before comparison, and empty filter values are\n * auto-removed.\n */\nexport const filterFn_endsWith = constructFilterFn({\n filter: (dataValue, filterValue) => Boolean(dataValue?.endsWith(filterValue)),\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val).toLowerCase(),\n resolveDataValue: (val: any) =>\n val == null ? undefined : String(val).toLowerCase(),\n})\n\n// Blank filters\n\n/**\n * Keeps rows whose column value is empty.\n *\n * A value is empty when it is nullish or stringifies to whitespace only. The\n * filter value acts as an on/off flag: `false` and blank values are\n * auto-removed.\n */\nexport const filterFn_empty = constructFilterFn({\n filter: (dataValue) => testValueEmpty(dataValue),\n autoRemove: (val: any) => testFalsy(val) || val === false,\n})\n\n/**\n * Keeps rows whose column value is not empty.\n *\n * A value is empty when it is nullish or stringifies to whitespace only. The\n * filter value acts as an on/off flag: `false` and blank values are\n * auto-removed.\n */\nexport const filterFn_notEmpty = constructFilterFn({\n filter: (dataValue) => !testValueEmpty(dataValue),\n autoRemove: (val: any) => testFalsy(val) || val === false,\n})\n\n// Number filters\n\n/**\n * Keeps rows whose value is greater than the filter value.\n *\n * Numeric values are compared numerically when both sides can be coerced to\n * numbers; otherwise normalized strings are compared.\n */\nexport const filterFn_greaterThan = constructFilterFn({\n filter: (dataValue, filterValue) =>\n compareGreaterThan(dataValue, filterValue),\n autoRemove: (val: any) => testFalsy(val),\n})\n\n/**\n * Keeps rows whose value is greater than or equal to the filter value.\n *\n * Delegates to the built-in greater-than and strict-equality comparisons.\n */\nexport const filterFn_greaterThanOrEqualTo = constructFilterFn({\n filter: (dataValue, filterValue) =>\n compareGreaterThanOrEqualTo(dataValue, filterValue),\n autoRemove: (val: any) => testFalsy(val),\n})\n\n/**\n * Keeps rows whose value is less than the filter value.\n *\n * This is implemented as the inverse of greater-than-or-equal comparison.\n */\nexport const filterFn_lessThan = constructFilterFn({\n filter: (dataValue, filterValue) =>\n !compareGreaterThanOrEqualTo(dataValue, filterValue),\n autoRemove: (val: any) => testFalsy(val),\n})\n\n/**\n * Keeps rows whose value is less than or equal to the filter value.\n *\n * This is implemented as the inverse of greater-than comparison.\n */\nexport const filterFn_lessThanOrEqualTo = constructFilterFn({\n filter: (dataValue, filterValue) =>\n !compareGreaterThan(dataValue, filterValue),\n autoRemove: (val: any) => testFalsy(val),\n})\n\n// Range filters\n\n/**\n * Keeps rows whose value falls between an exclusive min/max pair.\n *\n * Blank range endpoints are treated as open-ended.\n */\nexport const filterFn_between = constructFilterFn({\n filter: (dataValue, filterValues: [unknown, unknown]) =>\n compareBetween(dataValue, filterValues, false),\n autoRemove: (val: any) =>\n testFalsy(val) ||\n (Array.isArray(val) && testFalsy(val[0]) && testFalsy(val[1])),\n})\n\n/**\n * Keeps rows whose value falls between an inclusive min/max pair.\n *\n * Blank range endpoints are treated as open-ended.\n */\nexport const filterFn_betweenInclusive = constructFilterFn({\n filter: (dataValue, filterValues: [unknown, unknown]) =>\n compareBetween(dataValue, filterValues, true),\n autoRemove: (val: any) =>\n testFalsy(val) ||\n (Array.isArray(val) && testFalsy(val[0]) && testFalsy(val[1])),\n})\n\n/**\n * Keeps rows whose numeric value is inside an inclusive `[min, max]` range.\n *\n * Filter values are normalized so blank endpoints become open-ended and\n * reversed endpoints are swapped.\n */\nexport const filterFn_inNumberRange = constructFilterFn({\n filter: (dataValue: number, filterValue: [number, number]) => {\n const [min, max] = filterValue\n return dataValue >= min && dataValue <= max\n },\n resolveFilterValue: (val: [any, any]) => {\n const [unsafeMin, unsafeMax] = val\n\n const parsedMin =\n typeof unsafeMin !== 'number' ? parseFloat(unsafeMin) : unsafeMin\n const parsedMax =\n typeof unsafeMax !== 'number' ? parseFloat(unsafeMax) : unsafeMax\n\n let min =\n unsafeMin === null || Number.isNaN(parsedMin) ? -Infinity : parsedMin\n let max =\n unsafeMax === null || Number.isNaN(parsedMax) ? Infinity : parsedMax\n\n if (min > max) {\n const temp = min\n min = max\n max = temp\n }\n\n return [min, max] as const\n },\n autoRemove: (val: any) =>\n testFalsy(val) ||\n (Array.isArray(val) && testFalsy(val[0]) && testFalsy(val[1])),\n})\n\n// Date filters\n\n/**\n * Keeps rows whose date value is inside an inclusive `[min, max]` date range.\n *\n * Row values and range endpoints may be `Date` objects, timestamps, or\n * parseable date strings. Blank or invalid endpoints become open-ended and\n * reversed endpoints are swapped. Rows without a valid date never match.\n */\nexport const filterFn_inDateRange = constructFilterFn({\n filter: (dataValue: number, filterValue: [number, number]) => {\n const [min, max] = filterValue\n return dataValue >= min && dataValue <= max\n },\n resolveFilterValue: (val: [any, any]) => {\n const [unsafeMin, unsafeMax] = val\n\n const parsedMin = toDateTimestamp(unsafeMin)\n const parsedMax = toDateTimestamp(unsafeMax)\n\n let min = Number.isNaN(parsedMin) ? -Infinity : parsedMin\n let max = Number.isNaN(parsedMax) ? Infinity : parsedMax\n\n if (min > max) {\n const temp = min\n min = max\n max = temp\n }\n\n return [min, max] as const\n },\n resolveDataValue: (val: any) => toDateTimestamp(val),\n autoRemove: (val: any) =>\n testFalsy(val) ||\n (Array.isArray(val) && testFalsy(val[0]) && testFalsy(val[1])),\n})\n\n// Array filters\n\n/**\n * Keeps rows whose scalar column value equals at least one filter value.\n */\nexport const filterFn_arrHas = constructFilterFn({\n filter: (dataValue, filterValue: Array<unknown>) => {\n for (let i = 0; i < filterValue.length; i++) {\n if (dataValue === filterValue[i]) {\n return true\n }\n }\n return false\n },\n autoRemove: (val: any) => testFalsy(val) || !val?.length,\n})\n\n/**\n * Keeps rows whose array or string column value includes at least one filter value.\n */\nexport const filterFn_arrIncludes = constructFilterFn({\n filter: (dataValue, filterValue: Array<unknown>) => {\n if (typeof dataValue !== 'string' && !Array.isArray(dataValue)) {\n return false\n }\n\n for (let i = 0; i < filterValue.length; i++) {\n if (dataValue.includes(filterValue[i] as any)) {\n return true\n }\n }\n return false\n },\n autoRemove: (val: any) => testFalsy(val) || !val?.length,\n})\n\n/**\n * Keeps rows whose array column value includes every filter value.\n */\nexport const filterFn_arrIncludesAll = constructFilterFn({\n filter: (dataValue, filterValue: Array<unknown>) => {\n if (!Array.isArray(dataValue)) return false\n for (let i = 0; i < filterValue.length; i++) {\n if (!dataValue.includes(filterValue[i])) {\n return false\n }\n }\n return true\n },\n autoRemove: (val: any) => testFalsy(val) || !val?.length,\n})\n\n/**\n * Keeps rows whose array column value includes at least one filter value.\n */\nexport const filterFn_arrIncludesSome = constructFilterFn({\n filter: (dataValue, filterValue: Array<unknown>) => {\n if (!Array.isArray(dataValue)) return false\n for (let i = 0; i < filterValue.length; i++) {\n if (dataValue.includes(filterValue[i])) {\n return true\n }\n }\n return false\n },\n autoRemove: (val: any) => testFalsy(val) || !val?.length,\n})\n\n// Export\n\n/**\n * The built-in filter function registry.\n *\n * Registering this full object opts out of tree-shaking: every built-in\n * filter function ends up in your bundle. Prefer importing the `filterFn_*`\n * functions you actually use and registering just those in the `filterFns`\n * slot, or passing them directly to the `filterFn` column option.\n *\n * @deprecated Import individual `filterFn_*` functions instead for a smaller\n * bundle. This export still works and is not going away in v9, but built-in\n * name resolution (including `filterFn: 'auto'`) only finds functions you\n * register yourself.\n */\nexport const filterFns = {\n arrIncludes: filterFn_arrIncludes,\n arrIncludesAll: filterFn_arrIncludesAll,\n arrHas: filterFn_arrHas,\n arrIncludesSome: filterFn_arrIncludesSome,\n between: filterFn_between,\n betweenInclusive: filterFn_betweenInclusive,\n empty: filterFn_empty,\n endsWith: filterFn_endsWith,\n equals: filterFn_equals,\n equalsString: filterFn_equalsString,\n equalsStringSensitive: filterFn_equalsStringSensitive,\n inDateRange: filterFn_inDateRange,\n inNumberRange: filterFn_inNumberRange,\n includesString: filterFn_includesString,\n includesStringSensitive: filterFn_includesStringSensitive,\n notEmpty: filterFn_notEmpty,\n startsWith: filterFn_startsWith,\n weakEquals: filterFn_weakEquals,\n}\n\nexport type BuiltInFilterFn = keyof typeof filterFns\n\n// Utils\n\nfunction testFalsy(val: any) {\n return val === undefined || val === null || val === ''\n}\n\nfunction testValueEmpty(dataValue: any) {\n return dataValue == null || String(dataValue).trim() === ''\n}\n\nfunction toDateTimestamp(value: any): number {\n if (value instanceof Date) {\n return value.getTime()\n }\n if (typeof value === 'number') {\n return value\n }\n // Guard nullish and blank values explicitly: `new Date(null)` is the epoch,\n // not an invalid date.\n if (value == null || value === '') {\n return NaN\n }\n return new Date(value).getTime()\n}\n\nfunction compareGreaterThan(dataValue: any, filterValue: any): boolean {\n const numericDataValue = dataValue == null ? 0 : +dataValue\n const numericFilterValue = Number(filterValue)\n\n if (!isNaN(numericFilterValue) && !isNaN(numericDataValue)) {\n return numericDataValue > numericFilterValue\n }\n\n const stringDataValue = String(dataValue ?? '')\n .toLowerCase()\n .trim()\n const stringFilterValue = String(filterValue).toLowerCase().trim()\n return stringDataValue > stringFilterValue\n}\n\nfunction compareGreaterThanOrEqualTo(dataValue: any, filterValue: any) {\n return dataValue === filterValue || compareGreaterThan(dataValue, filterValue)\n}\n\nfunction compareBetween(\n dataValue: any,\n filterValues: [unknown, unknown],\n inclusive: boolean,\n): boolean {\n const min = filterValues[0]\n const hasMin = min !== '' && min !== undefined\n if (hasMin) {\n const passesMin = inclusive\n ? compareGreaterThanOrEqualTo(dataValue, min)\n : compareGreaterThan(dataValue, min)\n if (!passesMin) {\n return false\n }\n }\n\n const max = filterValues[1]\n if (max === '' || max === undefined) {\n return true\n }\n\n if (hasMin) {\n const numericMin = Number(min)\n const numericMax = Number(max)\n if (!isNaN(numericMin) && !isNaN(numericMax) && numericMin > numericMax) {\n return true\n }\n }\n\n return inclusive\n ? !compareGreaterThan(dataValue, max)\n : !compareGreaterThanOrEqualTo(dataValue, max)\n}\n"],"mappings":"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"}