@aftui/expresso
v1.0.6
Published
A powerful, themeable expression builder for creating complex filter logic
Readme
Expresso
A powerful, themeable expression builder for creating complex filter logic with a visual drag-and-drop interface.
Features
- 🎨 Fully Themeable - Injectable theme system with default light and dark themes
- 🔧 Comprehensive Operators - Comparison, arithmetic, logical, and conditional expressions
- 🎯 Drag & Drop - Intuitive interface for organizing expressions
- 💾 Presets - Save and load frequently used configurations
- 📋 Import/Export - Share expressions via JSON
- ⏱️ Undo/Redo - Full history support with keyboard shortcuts
- 🔍 Search - Find specific values within expressions
- ✅ Validation - Real-time error detection
Installation
npm install @aftui/expresso
# or
yarn add @aftui/expresso
# or
pnpm add @aftui/expressoPeer Dependencies
This package requires React 19+ and several peer dependencies:
npm install react react-dom sonner lucide-react @radix-ui/react-dropdown-menu @radix-ui/react-label @radix-ui/react-popover @radix-ui/react-select @radix-ui/react-switchImportant: This package uses Sonner for toast notifications. You must include the <Toaster /> component in your app:
import { Toaster } from 'sonner';
function App() {
return (
<>
<Toaster />
{/* Your app content */}
</>
);
}Styling
Expresso uses Vanilla Extract for styling, providing a zero-runtime CSS-in-JS solution. All styles are bundled with the component, so no additional setup is required.
SSR Frameworks (Astro, Next.js, Remix)
This component uses Radix UI which requires client-side rendering. When using with SSR frameworks:
Astro
---
import { Expresso } from '@aftui/expresso';
---
<Expresso
client:only="react"
fields={fields}
onApply={handleApply}
/>Next.js (App Router)
'use client' // Add this at the top of your component file
import { Expresso } from '@aftui/expresso'Next.js (Pages Router)
import dynamic from 'next/dynamic'
const Expresso = dynamic(
() => import('@aftui/expresso').then(mod => ({ default: mod.Expresso })),
{ ssr: false }
)Quick Start
import {
Expresso,
type JoinKeyExpression,
type DropdownItem
} from '@aftui/expresso';
import { Toaster } from 'sonner';
function App() {
const fields: DropdownItem[] = [
{ name: 'Price', key: 'price' },
{ name: 'Status', key: 'status' },
{ name: 'Category', key: 'category' },
];
const handleApply = (expression: JoinKeyExpression | JoinKeyExpression[]) => {
console.log('Filter expression:', expression);
// Use the expression in your application
};
return (
<>
<Toaster />
<Expresso
fields={fields}
onApply={handleApply}
onCancel={() => console.log('Cancelled')}
/>
</>
);
}Theming
Using Default Theme
<Expresso
fields={fields}
onApply={handleApply}
onCancel={handleCancel}
/>Using Dark Theme
import { Expresso, darkTheme } from '@aftui/expresso';
<Expresso
fields={fields}
onApply={handleApply}
onCancel={handleCancel}
theme={darkTheme}
/>Custom Theme
import {
Expresso,
type FilterBuilderThemeConfig
} from '@aftui/expresso';
const customTheme: FilterBuilderThemeConfig = {
theme: {
primary: "222.2 47.4% 11.2%",
accent: "142.1 76.2% 36.3%", // Green accent
// ... other theme properties
},
radius: "0.75rem",
};
<Expresso
theme={customTheme}
{...otherProps}
/>See THEMING.md for complete theming documentation.
Props
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| fields | DropdownItem[] | Yes | Array of available fields |
| onApply | (expression) => void | Yes | Callback when user applies filter |
| onCancel | () => void | Yes | Callback when user cancels |
| defaultExpression | JoinKeyExpression \| JoinKeyExpression[] | No | Initial expression |
| operatorConfig | OperatorConfig | No | Custom operator configuration |
| creationMetaData | CreationMetaData | No | Metadata for new expressions |
| customCategoryContent | Record<string, ReactNode> | No | Custom field category content |
| theme | FilterBuilderThemeConfig | No | Custom theme |
Expression Format
Expressions are structured JSON objects:
{
"operator": "and",
"expressions": [
{
"operator": "gt",
"left": { "valueType": "EnrichmentField", "fieldId": "Price" },
"right": { "valueType": "constant", "value": 100 }
},
{
"operator": "eq",
"left": { "valueType": "EnrichmentField", "fieldId": "Status" },
"right": { "valueType": "constant", "value": "Active" }
}
]
}Optional: Section Dropdown
If you need the Section Dropdown feature (for enrichment fields with sections), wrap your app with FieldsProvider:
import { FieldsProvider } from '@aftui/expresso';
function App() {
const enrichmentFields = [
{ Id: 1, Name: 'Field1', FriendlyName: 'Field 1', Key: 'field1', Section: 'General' },
// ... more fields
];
return (
<Expresso {...props} />
);
}If you don't use FieldsProvider, the Section Dropdown will simply not appear (graceful degradation).
TypeScript Support
This package is written in TypeScript and includes full type definitions.
import type {
JoinKeyExpression,
AnyExpressionType,
DropdownItem,
FilterBuilderThemeConfig,
OperatorConfig,
} from '@aftui/expresso';Backward Compatibility
For backward compatibility, the AdvancedFilterBuilder component name is also exported as an alias to Expresso. However, we recommend using Expresso for new projects:
// New (recommended)
import { Expresso } from '@aftui/expresso';
// Old (still works)
import { AdvancedFilterBuilder } from '@aftui/expresso';Browser Support
- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)
Repository
- GitHub: accessfintech/expresso
- NPM: @aftui/expresso
License
MIT
Contributing
Contributions are welcome! Please open an issue or pull request at the GitHub repository.
