@toolbox-web/grid 1.23.3 → 1.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -6
- package/all.d.ts +2 -2
- package/all.d.ts.map +1 -1
- package/all.js +2 -2
- package/all.js.map +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/lib/core/grid.d.ts +28 -0
- package/lib/core/grid.d.ts.map +1 -1
- package/lib/core/internal/feature-hook.d.ts +8 -0
- package/lib/core/internal/feature-hook.d.ts.map +1 -0
- package/lib/core/plugin/base-plugin.d.ts +14 -2
- package/lib/core/plugin/base-plugin.d.ts.map +1 -1
- package/lib/core/plugin/types.d.ts +2 -1
- package/lib/core/plugin/types.d.ts.map +1 -1
- package/lib/core/types.d.ts +68 -2
- package/lib/core/types.d.ts.map +1 -1
- package/lib/features/clipboard.d.ts +8 -0
- package/lib/features/clipboard.d.ts.map +1 -0
- package/lib/features/clipboard.js +2 -0
- package/lib/features/clipboard.js.map +1 -0
- package/lib/features/column-virtualization.d.ts +8 -0
- package/lib/features/column-virtualization.d.ts.map +1 -0
- package/lib/features/column-virtualization.js +2 -0
- package/lib/features/column-virtualization.js.map +1 -0
- package/lib/features/context-menu.d.ts +8 -0
- package/lib/features/context-menu.d.ts.map +1 -0
- package/lib/features/context-menu.js +2 -0
- package/lib/features/context-menu.js.map +1 -0
- package/lib/features/editing.d.ts +8 -0
- package/lib/features/editing.d.ts.map +1 -0
- package/lib/features/editing.js +2 -0
- package/lib/features/editing.js.map +1 -0
- package/lib/features/export.d.ts +8 -0
- package/lib/features/export.d.ts.map +1 -0
- package/lib/features/export.js +2 -0
- package/lib/features/export.js.map +1 -0
- package/lib/features/filtering.d.ts +8 -0
- package/lib/features/filtering.d.ts.map +1 -0
- package/lib/features/filtering.js +2 -0
- package/lib/features/filtering.js.map +1 -0
- package/lib/features/grouping-columns.d.ts +8 -0
- package/lib/features/grouping-columns.d.ts.map +1 -0
- package/lib/features/grouping-columns.js +2 -0
- package/lib/features/grouping-columns.js.map +1 -0
- package/lib/features/grouping-rows.d.ts +8 -0
- package/lib/features/grouping-rows.d.ts.map +1 -0
- package/lib/features/grouping-rows.js +2 -0
- package/lib/features/grouping-rows.js.map +1 -0
- package/lib/features/magic-string.es-CkyDP9Ir.mjs.map +1 -0
- package/lib/features/master-detail.d.ts +8 -0
- package/lib/features/master-detail.d.ts.map +1 -0
- package/lib/features/master-detail.js +2 -0
- package/lib/features/master-detail.js.map +1 -0
- package/lib/features/multi-sort.d.ts +10 -0
- package/lib/features/multi-sort.d.ts.map +1 -0
- package/lib/features/multi-sort.js +2 -0
- package/lib/features/multi-sort.js.map +1 -0
- package/lib/features/pinned-columns.d.ts +18 -0
- package/lib/features/pinned-columns.d.ts.map +1 -0
- package/lib/features/pinned-columns.js +2 -0
- package/lib/features/pinned-columns.js.map +1 -0
- package/lib/features/pinned-rows.d.ts +8 -0
- package/lib/features/pinned-rows.d.ts.map +1 -0
- package/lib/features/pinned-rows.js +2 -0
- package/lib/features/pinned-rows.js.map +1 -0
- package/lib/features/pivot.d.ts +8 -0
- package/lib/features/pivot.d.ts.map +1 -0
- package/lib/features/pivot.js +2 -0
- package/lib/features/pivot.js.map +1 -0
- package/lib/features/print.d.ts +8 -0
- package/lib/features/print.d.ts.map +1 -0
- package/lib/features/print.js +2 -0
- package/lib/features/print.js.map +1 -0
- package/lib/features/registry.d.ts +50 -0
- package/lib/features/registry.d.ts.map +1 -0
- package/lib/features/registry.js +2 -0
- package/lib/features/registry.js.map +1 -0
- package/lib/features/registry.spec.js +5 -0
- package/lib/features/registry.spec.js.map +1 -0
- package/lib/features/reorder-columns.d.ts +10 -0
- package/lib/features/reorder-columns.d.ts.map +1 -0
- package/lib/features/reorder-columns.js +2 -0
- package/lib/features/reorder-columns.js.map +1 -0
- package/lib/features/reorder-rows.d.ts +10 -0
- package/lib/features/reorder-rows.d.ts.map +1 -0
- package/lib/features/reorder-rows.js +2 -0
- package/lib/features/reorder-rows.js.map +1 -0
- package/lib/features/responsive.d.ts +8 -0
- package/lib/features/responsive.d.ts.map +1 -0
- package/lib/features/responsive.js +2 -0
- package/lib/features/responsive.js.map +1 -0
- package/lib/features/selection.d.ts +8 -0
- package/lib/features/selection.d.ts.map +1 -0
- package/lib/features/selection.js +2 -0
- package/lib/features/selection.js.map +1 -0
- package/lib/features/server-side.d.ts +8 -0
- package/lib/features/server-side.d.ts.map +1 -0
- package/lib/features/server-side.js +2 -0
- package/lib/features/server-side.js.map +1 -0
- package/lib/features/tree.d.ts +8 -0
- package/lib/features/tree.d.ts.map +1 -0
- package/lib/features/tree.js +2 -0
- package/lib/features/tree.js.map +1 -0
- package/lib/features/undo-redo.d.ts +8 -0
- package/lib/features/undo-redo.d.ts.map +1 -0
- package/lib/features/undo-redo.js +2 -0
- package/lib/features/undo-redo.js.map +1 -0
- package/lib/features/visibility.d.ts +8 -0
- package/lib/features/visibility.d.ts.map +1 -0
- package/lib/features/visibility.js +2 -0
- package/lib/features/visibility.js.map +1 -0
- package/lib/plugins/clipboard/ClipboardPlugin.d.ts +3 -3
- package/lib/plugins/clipboard/index.js +1 -1
- package/lib/plugins/clipboard/index.js.map +1 -1
- package/lib/plugins/clipboard/types.d.ts +1 -1
- package/lib/plugins/column-virtualization/index.js +1 -1
- package/lib/plugins/column-virtualization/index.js.map +1 -1
- package/lib/plugins/column-virtualization/types.d.ts +24 -2
- package/lib/plugins/column-virtualization/types.d.ts.map +1 -1
- package/lib/plugins/context-menu/index.js +1 -1
- package/lib/plugins/context-menu/index.js.map +1 -1
- package/lib/plugins/editing/index.js +1 -1
- package/lib/plugins/editing/index.js.map +1 -1
- package/lib/plugins/editing/types.d.ts +1 -1
- package/lib/plugins/export/ExportPlugin.d.ts +1 -1
- package/lib/plugins/export/index.js +1 -1
- package/lib/plugins/export/index.js.map +1 -1
- package/lib/plugins/export/types.d.ts +9 -1
- package/lib/plugins/export/types.d.ts.map +1 -1
- package/lib/plugins/filtering/index.js +1 -1
- package/lib/plugins/filtering/index.js.map +1 -1
- package/lib/plugins/filtering/types.d.ts +586 -29
- package/lib/plugins/filtering/types.d.ts.map +1 -1
- package/lib/plugins/grouping-columns/index.d.ts +1 -1
- package/lib/plugins/grouping-columns/index.js +1 -1
- package/lib/plugins/grouping-columns/index.js.map +1 -1
- package/lib/plugins/grouping-rows/index.d.ts +2 -2
- package/lib/plugins/grouping-rows/index.d.ts.map +1 -1
- package/lib/plugins/grouping-rows/index.js +1 -1
- package/lib/plugins/grouping-rows/index.js.map +1 -1
- package/lib/plugins/grouping-rows/types.d.ts +48 -3
- package/lib/plugins/grouping-rows/types.d.ts.map +1 -1
- package/lib/plugins/master-detail/MasterDetailPlugin.d.ts +2 -2
- package/lib/plugins/master-detail/index.js +1 -1
- package/lib/plugins/master-detail/index.js.map +1 -1
- package/lib/plugins/multi-sort/index.js +1 -1
- package/lib/plugins/multi-sort/index.js.map +1 -1
- package/lib/plugins/multi-sort/types.d.ts +40 -6
- package/lib/plugins/multi-sort/types.d.ts.map +1 -1
- package/lib/plugins/pinned-columns/index.js +1 -1
- package/lib/plugins/pinned-columns/index.js.map +1 -1
- package/lib/plugins/pinned-columns/types.d.ts +3 -3
- package/lib/plugins/pinned-rows/index.js +1 -1
- package/lib/plugins/pinned-rows/index.js.map +1 -1
- package/lib/plugins/pinned-rows/types.d.ts +42 -4
- package/lib/plugins/pinned-rows/types.d.ts.map +1 -1
- package/lib/plugins/pivot/index.js +1 -1
- package/lib/plugins/pivot/index.js.map +1 -1
- package/lib/plugins/pivot/types.d.ts +66 -1
- package/lib/plugins/pivot/types.d.ts.map +1 -1
- package/lib/plugins/print/PrintPlugin.d.ts +1 -1
- package/lib/plugins/print/index.js +1 -1
- package/lib/plugins/print/index.js.map +1 -1
- package/lib/plugins/print/types.d.ts +9 -1
- package/lib/plugins/print/types.d.ts.map +1 -1
- package/lib/plugins/{reorder → reorder-columns}/ReorderPlugin.d.ts +5 -3
- package/lib/plugins/reorder-columns/ReorderPlugin.d.ts.map +1 -0
- package/lib/plugins/reorder-columns/column-drag.d.ts.map +1 -0
- package/lib/plugins/{reorder → reorder-columns}/index.d.ts +2 -2
- package/lib/plugins/reorder-columns/index.d.ts.map +1 -0
- package/lib/plugins/reorder-columns/index.js +2 -0
- package/lib/plugins/reorder-columns/index.js.map +1 -0
- package/lib/plugins/{reorder → reorder-columns}/types.d.ts +17 -1
- package/lib/plugins/reorder-columns/types.d.ts.map +1 -0
- package/lib/plugins/{row-reorder → reorder-rows}/RowReorderPlugin.d.ts +5 -3
- package/lib/plugins/reorder-rows/RowReorderPlugin.d.ts.map +1 -0
- package/lib/plugins/{row-reorder → reorder-rows}/index.d.ts +2 -2
- package/lib/plugins/reorder-rows/index.d.ts.map +1 -0
- package/lib/plugins/reorder-rows/index.js +2 -0
- package/lib/plugins/reorder-rows/index.js.map +1 -0
- package/lib/plugins/{row-reorder → reorder-rows}/types.d.ts +5 -0
- package/lib/plugins/reorder-rows/types.d.ts.map +1 -0
- package/lib/plugins/responsive/ResponsivePlugin.d.ts +2 -2
- package/lib/plugins/responsive/index.js +1 -1
- package/lib/plugins/responsive/index.js.map +1 -1
- package/lib/plugins/selection/SelectionPlugin.d.ts +5 -5
- package/lib/plugins/selection/index.js +1 -1
- package/lib/plugins/selection/index.js.map +1 -1
- package/lib/plugins/server-side/index.js +1 -1
- package/lib/plugins/server-side/index.js.map +1 -1
- package/lib/plugins/server-side/types.d.ts +82 -0
- package/lib/plugins/server-side/types.d.ts.map +1 -1
- package/lib/plugins/tree/index.js +1 -1
- package/lib/plugins/tree/index.js.map +1 -1
- package/lib/plugins/undo-redo/index.js +1 -1
- package/lib/plugins/undo-redo/index.js.map +1 -1
- package/lib/plugins/visibility/VisibilityPlugin.d.ts +2 -2
- package/lib/plugins/visibility/index.js +1 -1
- package/lib/plugins/visibility/index.js.map +1 -1
- package/lib/plugins/visibility/types.d.ts +16 -2
- package/lib/plugins/visibility/types.d.ts.map +1 -1
- package/package.json +17 -2
- package/public.d.ts +9 -2
- package/public.d.ts.map +1 -1
- package/umd/grid.all.umd.js +1 -1
- package/umd/grid.all.umd.js.map +1 -1
- package/umd/grid.umd.js +1 -1
- package/umd/grid.umd.js.map +1 -1
- package/umd/plugins/clipboard.umd.js.map +1 -1
- package/umd/plugins/export.umd.js.map +1 -1
- package/umd/plugins/master-detail.umd.js.map +1 -1
- package/umd/plugins/print.umd.js.map +1 -1
- package/umd/plugins/reorder-columns.umd.js +2 -0
- package/umd/plugins/reorder-columns.umd.js.map +1 -0
- package/umd/plugins/reorder-rows.umd.js +2 -0
- package/umd/plugins/reorder-rows.umd.js.map +1 -0
- package/umd/plugins/responsive.umd.js.map +1 -1
- package/umd/plugins/selection.umd.js.map +1 -1
- package/umd/plugins/visibility.umd.js.map +1 -1
- package/lib/plugins/reorder/ReorderPlugin.d.ts.map +0 -1
- package/lib/plugins/reorder/column-drag.d.ts.map +0 -1
- package/lib/plugins/reorder/index.d.ts.map +0 -1
- package/lib/plugins/reorder/index.js +0 -2
- package/lib/plugins/reorder/index.js.map +0 -1
- package/lib/plugins/reorder/types.d.ts.map +0 -1
- package/lib/plugins/row-reorder/RowReorderPlugin.d.ts.map +0 -1
- package/lib/plugins/row-reorder/index.d.ts.map +0 -1
- package/lib/plugins/row-reorder/index.js +0 -2
- package/lib/plugins/row-reorder/index.js.map +0 -1
- package/lib/plugins/row-reorder/types.d.ts.map +0 -1
- package/umd/plugins/reorder.umd.js +0 -2
- package/umd/plugins/reorder.umd.js.map +0 -1
- package/umd/plugins/row-reorder.umd.js +0 -2
- package/umd/plugins/row-reorder.umd.js.map +0 -1
- /package/lib/plugins/{reorder → reorder-columns}/column-drag.d.ts +0 -0
|
@@ -127,9 +127,165 @@ export interface FilterParams {
|
|
|
127
127
|
/** Placeholder text for text inputs */
|
|
128
128
|
placeholder?: string;
|
|
129
129
|
}
|
|
130
|
-
/**
|
|
130
|
+
/**
|
|
131
|
+
* The category of filter applied to a column, which determines the available
|
|
132
|
+
* {@link FilterOperator operators} and the filter panel UI rendered.
|
|
133
|
+
*
|
|
134
|
+
* | Type | Panel UI | Compatible operators |
|
|
135
|
+
* |------|----------|---------------------|
|
|
136
|
+
* | `'text'` | Text input with operator dropdown | `contains`, `notContains`, `equals`, `notEquals`, `startsWith`, `endsWith`, `blank`, `notBlank` |
|
|
137
|
+
* | `'number'` | Range slider with min/max inputs | `lessThan`, `lessThanOrEqual`, `greaterThan`, `greaterThanOrEqual`, `between`, `blank`, `notBlank` |
|
|
138
|
+
* | `'date'` | Date pickers (from/to) | Same as `'number'` |
|
|
139
|
+
* | `'set'` | Checkbox list of unique values | `in`, `notIn`, `blank`, `notBlank` |
|
|
140
|
+
* | `'boolean'` | Checkbox list (`true` / `false` / `(Blank)`) | `in`, `notIn`, `blank`, `notBlank` |
|
|
141
|
+
*
|
|
142
|
+
* The grid auto-detects the filter type from the column's `type` property.
|
|
143
|
+
* Override by setting `filter.type` explicitly in the {@link FilterModel}.
|
|
144
|
+
*/
|
|
131
145
|
export type FilterType = 'text' | 'number' | 'date' | 'set' | 'boolean';
|
|
132
|
-
/**
|
|
146
|
+
/**
|
|
147
|
+
* Filter operators used in {@link FilterModel} to define how a cell value is compared
|
|
148
|
+
* against the filter value. Operators are grouped by the column types they apply to.
|
|
149
|
+
*
|
|
150
|
+
* **Multiple filters** on different columns use AND logic — a row must match all active filters.
|
|
151
|
+
*
|
|
152
|
+
* ---
|
|
153
|
+
*
|
|
154
|
+
* ## Text operators (`FilterType: 'text'`)
|
|
155
|
+
*
|
|
156
|
+
* Compare cell values as strings. **Case-insensitive by default** (controlled by `FilterConfig.caseSensitive`).
|
|
157
|
+
* Non-string cell values are coerced via `String()` before comparison.
|
|
158
|
+
*
|
|
159
|
+
* | Operator | Matches when | Example: filter = `"lic"` |
|
|
160
|
+
* |--|--|--|
|
|
161
|
+
* | `contains` | Cell value includes the filter as a substring | `"Alice"` ✓, `"Bob"` ✗ |
|
|
162
|
+
* | `notContains` | Cell value does **not** include the filter substring | `"Bob"` ✓, `"Alice"` ✗ |
|
|
163
|
+
* | `equals` | Cell value exactly equals the filter (after case normalization) | `"lic"` ✓, `"Alice"` ✗ |
|
|
164
|
+
* | `notEquals` | Cell value does **not** equal the filter | `"Alice"` ✓, `"lic"` ✗ |
|
|
165
|
+
* | `startsWith` | Cell value begins with the filter | filter `"Al"` → `"Alice"` ✓ |
|
|
166
|
+
* | `endsWith` | Cell value ends with the filter | filter `"ce"` → `"Alice"` ✓ |
|
|
167
|
+
*
|
|
168
|
+
* **When to use:**
|
|
169
|
+
* - `contains` — the default for free-text search fields; most intuitive for users
|
|
170
|
+
* - `equals` — when filtering on exact known values (e.g. status codes)
|
|
171
|
+
* - `startsWith` / `endsWith` — for prefix/suffix matching (e.g. file extensions, area codes)
|
|
172
|
+
* - `notContains` / `notEquals` — exclusion filters ("show everything except...")
|
|
173
|
+
*
|
|
174
|
+
* ---
|
|
175
|
+
*
|
|
176
|
+
* ## Blank operators (`FilterType: all`)
|
|
177
|
+
*
|
|
178
|
+
* These work universally across all filter types and check for **empty** values.
|
|
179
|
+
* They are evaluated first, before any type-specific logic.
|
|
180
|
+
*
|
|
181
|
+
* | Operator | Matches when | Does NOT match |
|
|
182
|
+
* |--|--|--|
|
|
183
|
+
* | `blank` | Cell is `null`, `undefined`, or `""` (empty string) | `0`, `false`, `NaN` |
|
|
184
|
+
* | `notBlank` | Cell has any non-null, non-empty value | `null`, `undefined`, `""` |
|
|
185
|
+
*
|
|
186
|
+
* **When to use:**
|
|
187
|
+
* - `blank` — find rows with missing data (e.g. "show incomplete records")
|
|
188
|
+
* - `notBlank` — exclude rows with missing data (e.g. "show only filled records")
|
|
189
|
+
*
|
|
190
|
+
* ---
|
|
191
|
+
*
|
|
192
|
+
* ## Numeric / date operators (`FilterType: 'number' | 'date'`)
|
|
193
|
+
*
|
|
194
|
+
* Compare values numerically. An internal `toNumeric()` conversion handles:
|
|
195
|
+
* - Numbers → used directly
|
|
196
|
+
* - `Date` objects → converted via `.getTime()` (milliseconds since epoch)
|
|
197
|
+
* - ISO date strings (e.g. `"2025-03-11"`) → parsed as `Date`, then `.getTime()`
|
|
198
|
+
* - Unparseable values → `NaN`, which fails all comparisons (row excluded)
|
|
199
|
+
*
|
|
200
|
+
* | Operator | Matches when (`cell` vs `filter.value`) |
|
|
201
|
+
* |--|--|
|
|
202
|
+
* | `lessThan` | `cell < value` |
|
|
203
|
+
* | `lessThanOrEqual` | `cell <= value` |
|
|
204
|
+
* | `greaterThan` | `cell > value` |
|
|
205
|
+
* | `greaterThanOrEqual` | `cell >= value` |
|
|
206
|
+
* | `between` | `value <= cell <= valueTo` (inclusive both ends) |
|
|
207
|
+
*
|
|
208
|
+
* The `between` operator requires both `filter.value` (min) and `filter.valueTo` (max).
|
|
209
|
+
* In the built-in UI:
|
|
210
|
+
* - **Number panels** render a dual-thumb range slider with min/max inputs
|
|
211
|
+
* - **Date panels** render "From" and "To" date pickers
|
|
212
|
+
*
|
|
213
|
+
* **When to use:**
|
|
214
|
+
* - `between` — range filters (age 25–35, dates in Q1, prices $10–$50)
|
|
215
|
+
* - `greaterThan` / `lessThan` — open-ended thresholds ("salary above 100k")
|
|
216
|
+
* - `greaterThanOrEqual` / `lessThanOrEqual` — inclusive thresholds
|
|
217
|
+
*
|
|
218
|
+
* ---
|
|
219
|
+
*
|
|
220
|
+
* ## Set operators (`FilterType: 'set' | 'boolean'`)
|
|
221
|
+
*
|
|
222
|
+
* Filter by inclusion/exclusion against a set of discrete values. The built-in filter panel
|
|
223
|
+
* shows a checkbox list of unique values; unchecked items form the excluded set.
|
|
224
|
+
*
|
|
225
|
+
* `filter.value` is an `unknown[]` array containing the set of values.
|
|
226
|
+
*
|
|
227
|
+
* | Operator | Matches when | Typical use |
|
|
228
|
+
* |--|--|--|
|
|
229
|
+
* | `notIn` | Cell value is **not** in the excluded array | Default for checkbox lists — unchecked items are excluded |
|
|
230
|
+
* | `in` | Cell value **is** in the included array | Explicit inclusion ("show only these") |
|
|
231
|
+
*
|
|
232
|
+
* **Blank handling:** Blank cells (`null`, `undefined`, `""`) are represented by the
|
|
233
|
+
* sentinel `BLANK_FILTER_VALUE` (`"(Blank)"`) in the values array. The panel renders a
|
|
234
|
+
* "(Blank)" checkbox; its checked/unchecked state controls whether blank rows are shown.
|
|
235
|
+
*
|
|
236
|
+
* **With `filterValue` extractor:** When a column defines `filterValue` to extract multiple
|
|
237
|
+
* values from a complex cell (e.g. an array of objects):
|
|
238
|
+
* - `notIn` — row is hidden if **any** extracted value is in the excluded set
|
|
239
|
+
* - `in` — row passes if **any** extracted value is in the included set
|
|
240
|
+
* - Empty extraction (no values) is treated as a blank cell
|
|
241
|
+
*
|
|
242
|
+
* **When to use:**
|
|
243
|
+
* - `notIn` — the default for set/boolean filters; maps naturally to "uncheck to hide"
|
|
244
|
+
* - `in` — when programmatically setting a filter to show only specific values
|
|
245
|
+
*
|
|
246
|
+
* ---
|
|
247
|
+
*
|
|
248
|
+
* ## Operator–type compatibility quick reference
|
|
249
|
+
*
|
|
250
|
+
* | Operator | text | number | date | set | boolean |
|
|
251
|
+
* |--|:--:|:--:|:--:|:--:|:--:|
|
|
252
|
+
* | `contains` | ✓ | | | | |
|
|
253
|
+
* | `notContains` | ✓ | | | | |
|
|
254
|
+
* | `equals` | ✓ | | | | |
|
|
255
|
+
* | `notEquals` | ✓ | | | | |
|
|
256
|
+
* | `startsWith` | ✓ | | | | |
|
|
257
|
+
* | `endsWith` | ✓ | | | | |
|
|
258
|
+
* | `blank` | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
259
|
+
* | `notBlank` | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
260
|
+
* | `lessThan` | | ✓ | ✓ | | |
|
|
261
|
+
* | `lessThanOrEqual` | | ✓ | ✓ | | |
|
|
262
|
+
* | `greaterThan` | | ✓ | ✓ | | |
|
|
263
|
+
* | `greaterThanOrEqual` | | ✓ | ✓ | | |
|
|
264
|
+
* | `between` | | ✓ | ✓ | | |
|
|
265
|
+
* | `in` | | | | ✓ | ✓ |
|
|
266
|
+
* | `notIn` | | | | ✓ | ✓ |
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```typescript
|
|
270
|
+
* // Text: free-text search on name column
|
|
271
|
+
* { field: 'name', type: 'text', operator: 'contains', value: 'alice' }
|
|
272
|
+
*
|
|
273
|
+
* // Number: salary above 100k
|
|
274
|
+
* { field: 'salary', type: 'number', operator: 'greaterThan', value: 100000 }
|
|
275
|
+
*
|
|
276
|
+
* // Date: hired in Q1 2025
|
|
277
|
+
* { field: 'hireDate', type: 'date', operator: 'between', value: '2025-01-01', valueTo: '2025-03-31' }
|
|
278
|
+
*
|
|
279
|
+
* // Set: show only Engineering and Sales departments
|
|
280
|
+
* { field: 'department', type: 'set', operator: 'in', value: ['Engineering', 'Sales'] }
|
|
281
|
+
*
|
|
282
|
+
* // Set: hide specific statuses (checkbox-style exclusion)
|
|
283
|
+
* { field: 'status', type: 'set', operator: 'notIn', value: ['Inactive', 'Archived'] }
|
|
284
|
+
*
|
|
285
|
+
* // Blank: find rows missing an email
|
|
286
|
+
* { field: 'email', type: 'text', operator: 'blank', value: '' }
|
|
287
|
+
* ```
|
|
288
|
+
*/
|
|
133
289
|
export type FilterOperator = 'contains' | 'notContains' | 'equals' | 'notEquals' | 'startsWith' | 'endsWith' | 'blank' | 'notBlank' | 'lessThan' | 'lessThanOrEqual' | 'greaterThan' | 'greaterThanOrEqual' | 'between' | 'in' | 'notIn';
|
|
134
290
|
/** Filter model representing a single filter condition */
|
|
135
291
|
export interface FilterModel {
|
|
@@ -144,27 +300,191 @@ export interface FilterModel {
|
|
|
144
300
|
/** Secondary value for 'between' operator */
|
|
145
301
|
valueTo?: unknown;
|
|
146
302
|
}
|
|
147
|
-
/**
|
|
303
|
+
/**
|
|
304
|
+
* Parameters passed to a custom {@link FilterPanelRenderer} when the filter panel
|
|
305
|
+
* opens for a column. Provides all the state and action callbacks needed to build
|
|
306
|
+
* a fully custom filter UI.
|
|
307
|
+
*
|
|
308
|
+
* The object is created fresh each time the panel opens and captures the current
|
|
309
|
+
* filter state for the column. Use the action methods (`applySetFilter`,
|
|
310
|
+
* `applyTextFilter`, `clearFilter`, `closePanel`) to drive filtering — they
|
|
311
|
+
* handle state updates, re-rendering, and panel lifecycle automatically.
|
|
312
|
+
*
|
|
313
|
+
* **Resolution priority** for filter panel renderers:
|
|
314
|
+
* 1. Plugin-level `filterPanelRenderer` (in `FilterConfig`)
|
|
315
|
+
* 2. Type-level `filterPanelRenderer` (in `typeDefaults`)
|
|
316
|
+
* 3. Built-in default panel (checkbox set filter, number range, or date range)
|
|
317
|
+
*
|
|
318
|
+
* Returning `undefined` from a plugin-level renderer falls through to the next
|
|
319
|
+
* level, so you can override only specific columns/fields while keeping defaults
|
|
320
|
+
* for the rest.
|
|
321
|
+
*
|
|
322
|
+
* **Framework adapters** wrap this for idiomatic usage:
|
|
323
|
+
* - **Angular**: Extend `BaseFilterPanel` — params are available as a signal input.
|
|
324
|
+
* - **React**: Use a single-argument `(params) => ReactNode` signature.
|
|
325
|
+
* - **Vue**: Use a single-argument `(params) => VNode` signature.
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* ```typescript
|
|
329
|
+
* // Vanilla: radio-button filter for a "status" column, default for everything else
|
|
330
|
+
* new FilteringPlugin({
|
|
331
|
+
* filterPanelRenderer: (container, params) => {
|
|
332
|
+
* if (params.field !== 'status') return undefined; // fall through to default
|
|
333
|
+
*
|
|
334
|
+
* const options = ['All', ...params.uniqueValues.map(String)];
|
|
335
|
+
* options.forEach(opt => {
|
|
336
|
+
* const label = document.createElement('label');
|
|
337
|
+
* label.style.display = 'block';
|
|
338
|
+
* const radio = document.createElement('input');
|
|
339
|
+
* radio.type = 'radio';
|
|
340
|
+
* radio.name = 'status';
|
|
341
|
+
* radio.checked = opt === 'All' && params.excludedValues.size === 0;
|
|
342
|
+
* radio.addEventListener('change', () => {
|
|
343
|
+
* if (opt === 'All') params.clearFilter();
|
|
344
|
+
* else params.applySetFilter(
|
|
345
|
+
* params.uniqueValues.filter(v => String(v) !== opt) as unknown[]
|
|
346
|
+
* );
|
|
347
|
+
* });
|
|
348
|
+
* label.append(radio, ` ${opt}`);
|
|
349
|
+
* container.appendChild(label);
|
|
350
|
+
* });
|
|
351
|
+
* },
|
|
352
|
+
* });
|
|
353
|
+
* ```
|
|
354
|
+
*
|
|
355
|
+
* @example
|
|
356
|
+
* ```typescript
|
|
357
|
+
* // React: custom slider filter via single-argument signature
|
|
358
|
+
* <DataGrid
|
|
359
|
+
* filtering={{
|
|
360
|
+
* filterPanelRenderer: (params) => (
|
|
361
|
+
* <MySliderFilter
|
|
362
|
+
* min={0} max={100}
|
|
363
|
+
* currentFilter={params.currentFilter}
|
|
364
|
+
* onApply={(min, max) => params.applyTextFilter('between', min, max)}
|
|
365
|
+
* onClear={() => params.clearFilter()}
|
|
366
|
+
* />
|
|
367
|
+
* ),
|
|
368
|
+
* }}
|
|
369
|
+
* />
|
|
370
|
+
* ```
|
|
371
|
+
*/
|
|
148
372
|
export interface FilterPanelParams {
|
|
149
|
-
/**
|
|
373
|
+
/**
|
|
374
|
+
* The field name (column key) being filtered.
|
|
375
|
+
* Matches {@link ColumnConfig.field} — use it to conditionally render
|
|
376
|
+
* different UIs for different columns in a shared renderer.
|
|
377
|
+
*/
|
|
150
378
|
field: string;
|
|
151
|
-
/**
|
|
379
|
+
/**
|
|
380
|
+
* The full column configuration for the filtered column.
|
|
381
|
+
* Useful for reading `column.type`, `column.filterParams`, `column.header`,
|
|
382
|
+
* or any other column metadata to tailor the filter panel UI.
|
|
383
|
+
*/
|
|
152
384
|
column: ColumnConfig;
|
|
153
|
-
/**
|
|
385
|
+
/**
|
|
386
|
+
* All unique values present in the current dataset for this field,
|
|
387
|
+
* sorted and de-duplicated. For columns with a `filterValue` extractor,
|
|
388
|
+
* these are the extracted/flattened values (not the raw cell values).
|
|
389
|
+
*
|
|
390
|
+
* When a `valuesHandler` is provided in the plugin config, this array
|
|
391
|
+
* contains the values returned by the handler instead of locally-extracted ones.
|
|
392
|
+
*
|
|
393
|
+
* Typical use: render checkboxes, radio buttons, or a searchable list.
|
|
394
|
+
*/
|
|
154
395
|
uniqueValues: unknown[];
|
|
155
|
-
/**
|
|
396
|
+
/**
|
|
397
|
+
* Currently excluded values for set-type (`notIn`) filters.
|
|
398
|
+
* An empty `Set` means no values are excluded (i.e., all values are shown).
|
|
399
|
+
*
|
|
400
|
+
* Use this to restore checkbox/toggle states when the panel re-opens.
|
|
401
|
+
* A value present in this set should appear **unchecked** in a set filter UI.
|
|
402
|
+
*/
|
|
156
403
|
excludedValues: Set<unknown>;
|
|
157
|
-
/**
|
|
404
|
+
/**
|
|
405
|
+
* The current search text the user has typed into the filter panel's
|
|
406
|
+
* search input (if any). Persisted across panel open/close cycles for
|
|
407
|
+
* the same field. Defaults to `''` when no search has been performed.
|
|
408
|
+
*
|
|
409
|
+
* Use this to pre-populate a search box if your custom panel includes one.
|
|
410
|
+
*/
|
|
158
411
|
searchText: string;
|
|
159
|
-
/**
|
|
412
|
+
/**
|
|
413
|
+
* The currently active {@link FilterModel} for this field, or `undefined`
|
|
414
|
+
* if no filter is applied. Inspect this to reflect the active filter state
|
|
415
|
+
* in your UI (e.g., highlight the active operator, show the current value).
|
|
416
|
+
*
|
|
417
|
+
* @example
|
|
418
|
+
* ```typescript
|
|
419
|
+
* if (params.currentFilter?.operator === 'between') {
|
|
420
|
+
* minInput.value = String(params.currentFilter.value);
|
|
421
|
+
* maxInput.value = String(params.currentFilter.valueTo);
|
|
422
|
+
* }
|
|
423
|
+
* ```
|
|
424
|
+
*/
|
|
160
425
|
currentFilter?: FilterModel;
|
|
161
|
-
/**
|
|
426
|
+
/**
|
|
427
|
+
* Apply a **set filter** (`notIn` operator) that excludes the given values.
|
|
428
|
+
* Rows whose field value is in `excludedValues` will be hidden.
|
|
429
|
+
*
|
|
430
|
+
* Calling this automatically closes the panel and triggers a filter-change event.
|
|
431
|
+
*
|
|
432
|
+
* Pass an empty array to clear the set filter (show all values).
|
|
433
|
+
*
|
|
434
|
+
* @param excludedValues - Array of values to exclude.
|
|
435
|
+
* @param valueTo - Optional metadata stored alongside the filter
|
|
436
|
+
* (e.g., a label, date range, or selected category). Accessible later
|
|
437
|
+
* via `FilterModel.valueTo` in the `filter-change` event or `currentFilter`.
|
|
438
|
+
*
|
|
439
|
+
* @example
|
|
440
|
+
* ```typescript
|
|
441
|
+
* // Exclude "Inactive" and "Archived" statuses
|
|
442
|
+
* params.applySetFilter(['Inactive', 'Archived']);
|
|
443
|
+
*
|
|
444
|
+
* // Exclude everything except the selected value
|
|
445
|
+
* const excluded = params.uniqueValues.filter(v => v !== selectedValue);
|
|
446
|
+
* params.applySetFilter(excluded as unknown[]);
|
|
447
|
+
* ```
|
|
448
|
+
*/
|
|
162
449
|
applySetFilter: (excludedValues: unknown[], valueTo?: unknown) => void;
|
|
163
|
-
/**
|
|
450
|
+
/**
|
|
451
|
+
* Apply a **text, number, or date filter** with the given operator and value(s).
|
|
452
|
+
*
|
|
453
|
+
* Calling this automatically closes the panel and triggers a filter-change event.
|
|
454
|
+
*
|
|
455
|
+
* @param operator - The filter operator to apply (e.g., `'contains'`,
|
|
456
|
+
* `'greaterThan'`, `'between'`). See {@link FilterOperator} for all options.
|
|
457
|
+
* @param value - The primary filter value.
|
|
458
|
+
* @param valueTo - Secondary value required by the `'between'` operator
|
|
459
|
+
* (defines the upper bound of the range).
|
|
460
|
+
*
|
|
461
|
+
* @example
|
|
462
|
+
* ```typescript
|
|
463
|
+
* // Text: contains search
|
|
464
|
+
* params.applyTextFilter('contains', searchInput.value);
|
|
465
|
+
*
|
|
466
|
+
* // Number: range between 10 and 100
|
|
467
|
+
* params.applyTextFilter('between', 10, 100);
|
|
468
|
+
*
|
|
469
|
+
* // Date: after a specific date
|
|
470
|
+
* params.applyTextFilter('greaterThan', '2025-01-01');
|
|
471
|
+
* ```
|
|
472
|
+
*/
|
|
164
473
|
applyTextFilter: (operator: FilterOperator, value: string | number, valueTo?: string | number) => void;
|
|
165
|
-
/**
|
|
474
|
+
/**
|
|
475
|
+
* Clear the active filter for this field entirely and close the panel.
|
|
476
|
+
* After calling, the column will show all rows (as if no filter was ever applied).
|
|
477
|
+
*
|
|
478
|
+
* Equivalent to removing the field's entry from the filter model.
|
|
479
|
+
*/
|
|
166
480
|
clearFilter: () => void;
|
|
167
|
-
/**
|
|
481
|
+
/**
|
|
482
|
+
* Close the filter panel **without** applying or clearing any filter.
|
|
483
|
+
* Use this for a "Cancel" / dismiss action where the user abandons changes.
|
|
484
|
+
*
|
|
485
|
+
* Note: `applySetFilter`, `applyTextFilter`, and `clearFilter` already close
|
|
486
|
+
* the panel automatically — you only need `closePanel` for explicit dismiss.
|
|
487
|
+
*/
|
|
168
488
|
closePanel: () => void;
|
|
169
489
|
}
|
|
170
490
|
/** Custom filter panel renderer function. Return undefined to use default panel for this column. */
|
|
@@ -211,17 +531,163 @@ export type FilterValuesHandler = (field: string, column: ColumnConfig) => Promi
|
|
|
211
531
|
* ```
|
|
212
532
|
*/
|
|
213
533
|
export type FilterHandler<TRow = unknown> = (filters: FilterModel[], currentRows: TRow[]) => TRow[] | Promise<TRow[]>;
|
|
214
|
-
/**
|
|
534
|
+
/**
|
|
535
|
+
* Configuration options for the {@link FilteringPlugin}.
|
|
536
|
+
*
|
|
537
|
+
* Pass this object to the `FilteringPlugin` constructor to customize filtering
|
|
538
|
+
* behavior, panel rendering, server-side integration, and state persistence.
|
|
539
|
+
*
|
|
540
|
+
* @typeParam TRow - The row data type. Inferred when using a typed `filterHandler`.
|
|
541
|
+
*
|
|
542
|
+
* @example
|
|
543
|
+
* ```typescript
|
|
544
|
+
* // Basic usage with defaults
|
|
545
|
+
* new FilteringPlugin()
|
|
546
|
+
*
|
|
547
|
+
* // Customized local filtering
|
|
548
|
+
* new FilteringPlugin({
|
|
549
|
+
* debounceMs: 200,
|
|
550
|
+
* caseSensitive: true,
|
|
551
|
+
* trackColumnState: true,
|
|
552
|
+
* })
|
|
553
|
+
*
|
|
554
|
+
* // Server-side filtering with custom values
|
|
555
|
+
* new FilteringPlugin<Employee>({
|
|
556
|
+
* valuesHandler: async (field) => {
|
|
557
|
+
* const res = await fetch(`/api/employees/distinct/${field}`);
|
|
558
|
+
* return res.json();
|
|
559
|
+
* },
|
|
560
|
+
* filterHandler: async (filters) => {
|
|
561
|
+
* const params = new URLSearchParams();
|
|
562
|
+
* filters.forEach(f => params.append(f.field, `${f.operator}:${f.value}`));
|
|
563
|
+
* const res = await fetch(`/api/employees?${params}`);
|
|
564
|
+
* return res.json();
|
|
565
|
+
* },
|
|
566
|
+
* })
|
|
567
|
+
* ```
|
|
568
|
+
*/
|
|
215
569
|
export interface FilterConfig<TRow = unknown> {
|
|
216
|
-
/**
|
|
570
|
+
/**
|
|
571
|
+
* Debounce delay in milliseconds for the search input inside the default
|
|
572
|
+
* filter panel. Controls how long the panel waits after the user stops
|
|
573
|
+
* typing before re-filtering the unique values list.
|
|
574
|
+
*
|
|
575
|
+
* Lower values feel more responsive but cause more DOM updates.
|
|
576
|
+
* Higher values reduce work for columns with many unique values.
|
|
577
|
+
*
|
|
578
|
+
* @default 300
|
|
579
|
+
*
|
|
580
|
+
* @example
|
|
581
|
+
* ```typescript
|
|
582
|
+
* // Faster response for small datasets
|
|
583
|
+
* new FilteringPlugin({ debounceMs: 100 })
|
|
584
|
+
*
|
|
585
|
+
* // Slower debounce for columns with thousands of unique values
|
|
586
|
+
* new FilteringPlugin({ debounceMs: 500 })
|
|
587
|
+
* ```
|
|
588
|
+
*/
|
|
217
589
|
debounceMs?: number;
|
|
218
|
-
/**
|
|
590
|
+
/**
|
|
591
|
+
* Whether text-based filtering comparisons are case-sensitive.
|
|
592
|
+
*
|
|
593
|
+
* When `false` (default), `"alice"` matches `"Alice"`, `"ALICE"`, etc.
|
|
594
|
+
* When `true`, only exact case matches pass the filter.
|
|
595
|
+
*
|
|
596
|
+
* Affects both:
|
|
597
|
+
* - The core `filterRows()` logic (text operators like `contains`, `equals`, etc.)
|
|
598
|
+
* - The search input inside the default filter panel (value list filtering)
|
|
599
|
+
*
|
|
600
|
+
* @default false
|
|
601
|
+
*
|
|
602
|
+
* @example
|
|
603
|
+
* ```typescript
|
|
604
|
+
* // Enable case-sensitive filtering
|
|
605
|
+
* new FilteringPlugin({ caseSensitive: true })
|
|
606
|
+
* ```
|
|
607
|
+
*/
|
|
219
608
|
caseSensitive?: boolean;
|
|
220
|
-
/**
|
|
609
|
+
/**
|
|
610
|
+
* Whether to trim leading/trailing whitespace from filter input values
|
|
611
|
+
* before applying them.
|
|
612
|
+
*
|
|
613
|
+
* @default true
|
|
614
|
+
*
|
|
615
|
+
* @remarks
|
|
616
|
+
* **Reserved for future use.** This option is accepted in configuration
|
|
617
|
+
* but not yet applied in the current filtering implementation.
|
|
618
|
+
*/
|
|
221
619
|
trimInput?: boolean;
|
|
222
|
-
/**
|
|
620
|
+
/**
|
|
621
|
+
* Whether to offload filtering to a Web Worker for large datasets.
|
|
622
|
+
*
|
|
623
|
+
* @default true
|
|
624
|
+
*
|
|
625
|
+
* @remarks
|
|
626
|
+
* **Reserved for future use.** This option is accepted in configuration
|
|
627
|
+
* but not yet implemented. Filtering currently runs synchronously on
|
|
628
|
+
* the main thread for all dataset sizes. Performance is excellent for
|
|
629
|
+
* most use cases — the grid handles 10,000+ rows without noticeable delay
|
|
630
|
+
* thanks to result caching and debounced input.
|
|
631
|
+
*
|
|
632
|
+
* When implemented, this will automatically offload `filterRows()` to a
|
|
633
|
+
* Web Worker when the row count exceeds an internal threshold, keeping
|
|
634
|
+
* the main thread responsive during heavy filtering operations.
|
|
635
|
+
*/
|
|
223
636
|
useWorker?: boolean;
|
|
224
|
-
/**
|
|
637
|
+
/**
|
|
638
|
+
* Custom filter panel renderer that replaces the built-in panel content
|
|
639
|
+
* for **all** columns (unless you return `undefined` for specific columns
|
|
640
|
+
* to fall through to the next level).
|
|
641
|
+
*
|
|
642
|
+
* **Resolution priority** (first non-empty result wins):
|
|
643
|
+
* 1. This plugin-level `filterPanelRenderer`
|
|
644
|
+
* 2. Type-level `filterPanelRenderer` (in `gridConfig.typeDefaults[type]`)
|
|
645
|
+
* 3. Built-in panel (checkbox set filter, number range slider, or date picker)
|
|
646
|
+
*
|
|
647
|
+
* The renderer receives the panel container element and a {@link FilterPanelParams}
|
|
648
|
+
* object with state and action callbacks. Append your UI to the container.
|
|
649
|
+
*
|
|
650
|
+
* **Return `undefined`** (or leave the container empty) to fall through to
|
|
651
|
+
* the next resolution level. This lets you override only specific fields.
|
|
652
|
+
*
|
|
653
|
+
* @example
|
|
654
|
+
* ```typescript
|
|
655
|
+
* // Override only the "status" column, use defaults for everything else
|
|
656
|
+
* new FilteringPlugin({
|
|
657
|
+
* filterPanelRenderer: (container, params) => {
|
|
658
|
+
* if (params.field !== 'status') return undefined; // fall through
|
|
659
|
+
*
|
|
660
|
+
* params.uniqueValues.forEach(val => {
|
|
661
|
+
* const btn = document.createElement('button');
|
|
662
|
+
* btn.textContent = String(val);
|
|
663
|
+
* btn.onclick = () => {
|
|
664
|
+
* const excluded = params.uniqueValues.filter(v => v !== val);
|
|
665
|
+
* params.applySetFilter(excluded as unknown[]);
|
|
666
|
+
* };
|
|
667
|
+
* container.appendChild(btn);
|
|
668
|
+
* });
|
|
669
|
+
* },
|
|
670
|
+
* })
|
|
671
|
+
* ```
|
|
672
|
+
*
|
|
673
|
+
* @example
|
|
674
|
+
* ```typescript
|
|
675
|
+
* // Replace ALL filter panels with a custom component
|
|
676
|
+
* new FilteringPlugin({
|
|
677
|
+
* filterPanelRenderer: (container, params) => {
|
|
678
|
+
* const myFilter = new MyCustomFilterElement();
|
|
679
|
+
* myFilter.field = params.field;
|
|
680
|
+
* myFilter.values = params.uniqueValues;
|
|
681
|
+
* myFilter.onApply = (excluded) => params.applySetFilter(excluded);
|
|
682
|
+
* myFilter.onClear = () => params.clearFilter();
|
|
683
|
+
* container.appendChild(myFilter);
|
|
684
|
+
* },
|
|
685
|
+
* })
|
|
686
|
+
* ```
|
|
687
|
+
*
|
|
688
|
+
* @see {@link FilterPanelParams} for all available state and action callbacks.
|
|
689
|
+
* @see {@link FilterPanelRenderer} for the function signature.
|
|
690
|
+
*/
|
|
225
691
|
filterPanelRenderer?: FilterPanelRenderer;
|
|
226
692
|
/**
|
|
227
693
|
* Whether filter state should be included in column state persistence.
|
|
@@ -229,28 +695,119 @@ export interface FilterConfig<TRow = unknown> {
|
|
|
229
695
|
* When `true`:
|
|
230
696
|
* - `getColumnState()` includes filter data for each column
|
|
231
697
|
* - Filter changes fire the `column-state-change` event (debounced)
|
|
232
|
-
* - `applyColumnState()` restores filter state
|
|
698
|
+
* - `applyColumnState()` restores filter state from a saved snapshot
|
|
233
699
|
*
|
|
234
700
|
* When `false` (default):
|
|
235
701
|
* - Filters are excluded from column state entirely
|
|
236
|
-
* - Filter changes do not fire `column-state-change`
|
|
702
|
+
* - Filter changes do **not** fire `column-state-change`
|
|
703
|
+
*
|
|
704
|
+
* Enable this when you persist column state (e.g., to localStorage or a server)
|
|
705
|
+
* and want filter selections to survive page reloads.
|
|
237
706
|
*
|
|
238
707
|
* @default false
|
|
708
|
+
*
|
|
709
|
+
* @example
|
|
710
|
+
* ```typescript
|
|
711
|
+
* // Persist filters alongside column order, widths, and sort state
|
|
712
|
+
* new FilteringPlugin({ trackColumnState: true })
|
|
713
|
+
*
|
|
714
|
+
* // Save/restore cycle:
|
|
715
|
+
* const state = grid.getColumnState(); // includes filter data
|
|
716
|
+
* localStorage.setItem('grid-state', JSON.stringify(state));
|
|
717
|
+
* // ... later ...
|
|
718
|
+
* grid.applyColumnState(JSON.parse(localStorage.getItem('grid-state')!));
|
|
719
|
+
* ```
|
|
239
720
|
*/
|
|
240
721
|
trackColumnState?: boolean;
|
|
241
722
|
/**
|
|
242
|
-
* Async handler for fetching unique values from a server.
|
|
243
|
-
*
|
|
244
|
-
*
|
|
723
|
+
* Async handler for fetching unique filter values from a server.
|
|
724
|
+
*
|
|
725
|
+
* When provided, this handler is called **each time a filter panel opens**
|
|
726
|
+
* instead of extracting unique values from the locally-loaded rows. The panel
|
|
727
|
+
* shows a loading indicator while the handler resolves.
|
|
728
|
+
*
|
|
729
|
+
* Use this for server-side or paginated datasets where the client only holds
|
|
730
|
+
* a subset of the data and the local unique values would be incomplete.
|
|
731
|
+
*
|
|
732
|
+
* The returned values populate `FilterPanelParams.uniqueValues` and appear
|
|
733
|
+
* in the checkbox list (or are passed to your custom `filterPanelRenderer`).
|
|
734
|
+
*
|
|
735
|
+
* @example
|
|
736
|
+
* ```typescript
|
|
737
|
+
* new FilteringPlugin({
|
|
738
|
+
* valuesHandler: async (field, column) => {
|
|
739
|
+
* const res = await fetch(`/api/data/distinct/${field}`);
|
|
740
|
+
* return res.json(); // ['Engineering', 'Marketing', 'Sales', ...]
|
|
741
|
+
* },
|
|
742
|
+
* })
|
|
743
|
+
* ```
|
|
744
|
+
*
|
|
745
|
+
* @example
|
|
746
|
+
* ```typescript
|
|
747
|
+
* // Combine with filterHandler for full server-side filtering
|
|
748
|
+
* new FilteringPlugin<Employee>({
|
|
749
|
+
* valuesHandler: async (field) => {
|
|
750
|
+
* const res = await fetch(`/api/employees/distinct/${field}`);
|
|
751
|
+
* return res.json();
|
|
752
|
+
* },
|
|
753
|
+
* filterHandler: async (filters) => {
|
|
754
|
+
* const body = JSON.stringify(filters);
|
|
755
|
+
* const res = await fetch('/api/employees/filter', { method: 'POST', body });
|
|
756
|
+
* return res.json();
|
|
757
|
+
* },
|
|
758
|
+
* })
|
|
759
|
+
* ```
|
|
760
|
+
*
|
|
761
|
+
* @see {@link FilterValuesHandler} for the full type signature.
|
|
245
762
|
*/
|
|
246
763
|
valuesHandler?: FilterValuesHandler;
|
|
247
764
|
/**
|
|
248
|
-
* Async handler for
|
|
249
|
-
*
|
|
250
|
-
*
|
|
765
|
+
* Async handler for delegating filtering to a server.
|
|
766
|
+
*
|
|
767
|
+
* When provided, the plugin's `processRows()` hook becomes a **passthrough**
|
|
768
|
+
* (returns rows unfiltered) and instead calls this handler whenever the
|
|
769
|
+
* active filters change. The handler should return the filtered rows, which
|
|
770
|
+
* replace the grid's current data.
|
|
771
|
+
*
|
|
772
|
+
* This enables full server-side filtering for large datasets that can't be
|
|
773
|
+
* loaded into the browser. The handler receives the complete list of active
|
|
774
|
+
* {@link FilterModel} objects and the current row array (useful for optimistic
|
|
775
|
+
* updates or reference).
|
|
776
|
+
*
|
|
777
|
+
* The handler may return rows synchronously (plain array) or asynchronously
|
|
778
|
+
* (Promise). While an async handler is pending, the grid retains its current
|
|
779
|
+
* rows until the new data arrives.
|
|
780
|
+
*
|
|
781
|
+
* @example
|
|
782
|
+
* ```typescript
|
|
783
|
+
* // Server-side filtering with query params
|
|
784
|
+
* new FilteringPlugin<Employee>({
|
|
785
|
+
* filterHandler: async (filters, currentRows) => {
|
|
786
|
+
* const params = new URLSearchParams();
|
|
787
|
+
* filters.forEach(f => params.append(f.field, `${f.operator}:${f.value}`));
|
|
788
|
+
* const res = await fetch(`/api/employees?${params}`);
|
|
789
|
+
* return res.json();
|
|
790
|
+
* },
|
|
791
|
+
* })
|
|
792
|
+
* ```
|
|
793
|
+
*
|
|
794
|
+
* @example
|
|
795
|
+
* ```typescript
|
|
796
|
+
* // POST-based filtering with full filter models
|
|
797
|
+
* new FilteringPlugin<Product>({
|
|
798
|
+
* filterHandler: async (filters) => {
|
|
799
|
+
* const res = await fetch('/api/products/filter', {
|
|
800
|
+
* method: 'POST',
|
|
801
|
+
* headers: { 'Content-Type': 'application/json' },
|
|
802
|
+
* body: JSON.stringify({ filters }),
|
|
803
|
+
* });
|
|
804
|
+
* return res.json();
|
|
805
|
+
* },
|
|
806
|
+
* })
|
|
807
|
+
* ```
|
|
251
808
|
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
809
|
+
* @see {@link FilterHandler} for the full type signature.
|
|
810
|
+
* @see {@link FilterChangeDetail} for the event emitted after filter changes.
|
|
254
811
|
*/
|
|
255
812
|
filterHandler?: FilterHandler<TRow>;
|
|
256
813
|
}
|