@taruvi/react-filters
v0.1.1
Published
Visual filter builder for Taruvi apps — wraps Kendo React Filter and outputs CrudFilters
Downloads
514
Maintainers
Readme
@taruvi/react-filters
A visual filter builder for Taruvi apps. Wraps Kendo React Filter and outputs a CrudFilters list — the format accepted natively by the Taruvi data API and @taruvi/refine-providers.
Features
- Visual AND/OR filter builder — nested groups, add/remove rows, switch logic
- 10 field types — string, integer, number, boolean, date, datetime, time, enum, uuid, array
- Rich operator set — comparison, string matching, between, null checks, array ops (
acontains,aoverlap, …), range ops (rcontains,rcontainedby, …) - Async FK lookups — debounced, abort-safe search; displays whatever
loadOptionsreturns - Operator-aware value editors — single input, date picker, pair pickers for between/range, multi-select for
in/array ops - Controlled & uncontrolled — works with
useState, Refine'suseDataGrid, or any filter state manager - TypeScript-first — full types for all props, field configs, and filter output
Requirements
- React ≥ 18
- A Kendo React license (commercial or trial)
Install
npm install @taruvi/react-filters
# or
bun add @taruvi/react-filtersKendo UI packages are bundled as dependencies and installed automatically. Import the theme CSS once in your app entry:
import '@progress/kendo-theme-default/dist/default-ocean-blue.css'Other swatches: @progress/kendo-theme-default/dist/default-main.css, default-nordic.css, etc.
Quick start
import { useState } from 'react'
import {
TaruviFilterBuilder,
type CrudFilterList,
type TaruviFieldConfig,
} from '@taruvi/react-filters'
import '@progress/kendo-theme-default/dist/default-ocean-blue.css'
const fields: TaruviFieldConfig[] = [
{ name: 'name', label: 'Name', type: 'string' },
{ name: 'score', label: 'Score', type: 'integer' },
{
name: 'status',
label: 'Status',
type: 'enum',
enumValues: [
{ label: 'Active', value: 'active' },
{ label: 'Inactive', value: 'inactive' },
],
},
{ name: 'created_at', label: 'Created At', type: 'datetime' },
]
function MyPage() {
const [filters, setFilters] = useState<CrudFilterList>([])
return (
<TaruviFilterBuilder
fields={fields}
value={filters}
onChange={setFilters}
/>
)
}Output format
onChange emits a CrudFilterList — a flat-or-nested array compatible with Refine's CrudFilters and the Taruvi backend filter parser.
// Simple leaf
[{ field: 'status', operator: 'eq', value: 'active' }]
// OR group
[{
operator: 'or',
value: [
{ field: 'status', operator: 'eq', value: 'active' },
{ field: 'status', operator: 'eq', value: 'pending' },
],
}]
// AND range
[{
operator: 'and',
value: [
{ field: 'score', operator: 'gte', value: 60 },
{ field: 'score', operator: 'lte', value: 90 },
],
}]
// Between (single value, comma-separated)
[{ field: 'score', operator: 'between', value: '60,90' }]
// Null check
[{ field: 'email', operator: 'null', value: true }]Sending to the API
Pass filters directly to @taruvi/refine-providers — it handles serialisation automatically:
const { dataGridProps, setFilters } = useDataGrid({ resource: 'employees' })
setFilters(filters) // CrudFilterList from TaruviFilterBuilderTaruviFilterBuilder props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| fields | TaruviFieldConfig[] | — | Field definitions (required) |
| value | CrudFilterList | — | Controlled filter value |
| defaultValue | CrudFilterList | — | Uncontrolled initial value |
| onChange | (filters: CrudFilterList) => void | — | Called with valid filters on every change |
| operatorPreset | 'minimal' \| 'standard' \| 'full' | 'standard' | Default operator set for all fields |
| loadOptions | LoadFieldOptionsFn | — | Fallback async loader shared across all lookup fields |
| className | string | — | CSS class on the filter root |
| style | CSSProperties | — | Inline styles on the filter root |
TaruviFieldConfig
interface TaruviFieldConfig {
name: string // Field name as it appears in the API (e.g. 'created_by_id')
label: string // Human-readable display label
type: TaruviFieldType // See field types below
operators?: string[] // Override the operator list for this field
enumValues?: TaruviEnumOption[] // Static options for 'enum' fields
loadOptions?: LoadFieldOptionsFn // Async loader for FK / lookup fields
minSearchLength?: number // Min chars before loadOptions fires (default: 0 = load on open)
filterable?: boolean // Exclude from filter UI (default: true)
}Field types
| Type | Input | Use for |
|------|-------|---------|
| string | Text box | Names, descriptions, text fields |
| integer | Numeric | Counts, IDs, year values |
| number | Numeric | Decimals, prices, scores |
| boolean | Dropdown | True/false flags |
| date | Date picker | Date-only fields |
| datetime | DateTime picker | Timestamps |
| time | Time picker | Time-only fields |
| enum | Dropdown | Fixed option lists (status, category) |
| uuid | Combobox | FK fields by ID (use loadOptions for labels) |
| array | Multi-select | Array columns (tags, labels) |
Async FK lookups (loadOptions)
For FK fields where you want to search by label (e.g. "Assignee"), provide loadOptions:
import type { LoadFieldOptionsFn } from '@taruvi/react-filters'
const loadUserOptions: LoadFieldOptionsFn = async ({ searchText, signal }) => {
const res = await fetch(`/api/users/?search=${searchText}`, { signal })
const data = await res.json()
return data.results.map((u: User) => ({ label: u.name, value: u.id }))
}
const fields: TaruviFieldConfig[] = [
{
name: 'assigned_to_id',
label: 'Assignee',
type: 'uuid',
loadOptions: loadUserOptions,
minSearchLength: 2, // start searching after 2 characters
},
]The component handles debouncing, abort-on-unmount, result caching, and showing a loading spinner while resolving selected labels.
Operator presets
| Preset | Operators included |
|--------|--------------------|
| minimal | eq, ne, contains, gt, lt, null, nnull |
| standard (default) | comparison + string matching + in + between + null |
| full | All operators including array (acontains, aelement, …) and range (rcontains, rcontainedby, …) |
Override per-field with the operators array:
{
name: 'experience_years',
label: 'Experience',
type: 'integer',
operators: ['rcontains', 'rcontainedby', 'gte', 'lte'],
}Exports
Components
| Export | Description |
|--------|-------------|
| TaruviFilterBuilder | Main filter builder component |
| TaruviFilterBuilderProps | Props type |
Operator utilities
| Export | Description |
|--------|-------------|
| OPERATOR_PRESETS | Record of preset → operator list |
| TYPE_DEFAULT_OPERATORS | Default operators per field type |
| resolveFieldOperators | Resolve operators for a type + preset |
Types
CrudFilterList, CrudFilterItem, CrudFilterGroup, TaruviFieldConfig, TaruviFieldType, TaruviEnumOption, LoadFieldOptionsFn, LoadFieldOptionsContext, ValueEditorContext, OperatorPreset
Development
bun install
bun run test # unit tests
bun run build # library build → dist/
bun run lint # eslintTo test in a consuming app, link via a local path reference:
"@taruvi/react-filters": "file:../taruvi-filter-builder"