Calendar/docs/fuzzy-search-filter-system.md

195 lines
6.7 KiB
Markdown
Raw Normal View History

# Fuzzy Search Filter System
## Overview
The calendar includes a powerful fuzzy search filter system that allows users to quickly find events by typing partial matches of event titles or descriptions. The system dims non-matching events while keeping matching events fully visible, providing instant visual feedback.
## Features
- **Real-time fuzzy search** using Fuse.js library
- **Visual filtering** with opacity-based dimming (0.2 for non-matches, 1.0 for matches)
- **Minimum character threshold** (2 characters) handled by Fuse.js configuration
- **Cross-navigation persistence** - filter applies to pre-rendered grids during navigation
- **Escape key support** for quick filter clearing
- **Performance optimized** with requestAnimationFrame debouncing
## Architecture
### Core Components
#### EventFilterManager (`src/managers/EventFilterManager.ts`)
Central component responsible for:
- Managing search input event listeners
- Performing fuzzy search with Fuse.js
- Coordinating visual updates across all event containers
- Emitting filter change events via EventBus
#### CSS-based Visual System
```css
/* Dim all events when filter is active */
swp-events-layer[data-filter-active="true"] swp-event {
opacity: 0.2;
transition: opacity 200ms ease;
}
/* Keep matching events fully visible */
swp-events-layer[data-filter-active="true"] swp-event[data-matches="true"] {
opacity: 1;
}
```
#### Pre-rendered Grid Support
- NavigationManager listens for `FILTER_CHANGED` events
- NavigationRenderer applies filter state to all grid containers
- Ensures filter persists when navigating between time periods
### Event Flow
1. **User Input** → Search field receives input
2. **Debounced Processing** → RequestAnimationFrame prevents excessive filtering
3. **Fuzzy Search** → Fuse.js performs search against event titles/descriptions
4. **DOM Updates** → Matching events marked with `data-matches="true"`
5. **CSS Application** → Non-matching events automatically dimmed via CSS rules
6. **Cross-Grid Sync** → Filter applied to all pre-rendered grids
## Configuration
### Fuse.js Settings
```typescript
const fuseOptions = {
keys: ['title', 'description'], // Search in title and description
threshold: 0.3, // 0 = exact match, 1 = match anything
includeScore: true, // Include relevance scores
minMatchCharLength: 2, // Minimum 2 characters for match
shouldSort: true, // Sort by relevance
ignoreLocation: true // Search anywhere in string
};
```
### CSS Variables
```css
:root {
--filter-dimmed-opacity: 0.2; /* Opacity for non-matching events */
--filter-transition: 200ms ease; /* Smooth opacity transitions */
}
```
## Integration Points
### CalendarManager
```typescript
// EventFilterManager is initialized in CalendarManager constructor
this.eventFilterManager = new EventFilterManager();
```
### EventRenderer
```typescript
// Events emit EVENTS_RENDERED for filter system to track
this.eventBus.emit(CoreEvents.EVENTS_RENDERED, {
events: events,
container: context.container
});
```
### HTML Structure
```html
<swp-search-container>
<input type="search" placeholder="Search events..." />
</swp-search-container>
```
## User Experience
### Search Behavior
- **No input**: All events visible at full opacity
- **1 character**: Filter active, but Fuse.js won't return matches (by design)
- **2+ characters**: Real-time fuzzy matching with visual feedback
- **Empty field**: Filter cleared, all events return to normal
- **Escape key**: Immediate filter clearing
### Visual Feedback
- **Search field styling**: Border color changes when filter is active
- **Event dimming**: Non-matching events fade to 20% opacity
- **Smooth transitions**: 200ms ease transitions for polished feel
## Performance Considerations
### Optimization Strategies
1. **RequestAnimationFrame debouncing** prevents excessive search operations
2. **CSS-based visual updates** leverage browser's rendering pipeline
3. **Event delegation** avoids per-event listener overhead
4. **Efficient DOM queries** using attribute selectors
### Memory Management
- Event listeners properly scoped to component lifecycle
- Fuse.js instance recreated only when event data changes
- Minimal DOM manipulation through attribute-based CSS rules
## Error Handling
### Graceful Degradation
- System continues to function if Fuse.js fails to load
- Search input remains functional for basic text entry
- Console warnings for debugging (removed in production)
### Edge Cases
- **No events to search**: Filter system remains inactive
- **Empty search results**: All events dimmed (expected behavior)
- **DOM timing issues**: Waits for DOM readiness before initialization
## Future Enhancements
### Potential Improvements
- **Search result highlighting** within event text
- **Advanced filters** (date range, event type, etc.)
- **Search history** with dropdown suggestions
- **Keyboard navigation** through search results
- **Search analytics** for usage insights
### Performance Optimizations
- **Virtual scrolling** for large event sets
- **Search index caching** for repeated queries
- **Web Workers** for heavy search operations
## Dependencies
### External Libraries
- **Fuse.js** (v7.x) - Fuzzy search library
- License: Apache 2.0
- File: `wwwroot/js/lib/fuse.min.mjs`
- Import: ES module format
### Internal Dependencies
- **EventBus** - Inter-component communication
- **CoreEvents** - Centralized event type definitions
- **CalendarEvent** - Event data type definitions
## Testing Considerations
### Test Scenarios
1. **Basic search functionality** - Verify fuzzy matching works
2. **Performance testing** - Large event sets (1000+ events)
3. **Cross-navigation** - Filter persistence during navigation
4. **Edge cases** - Empty results, special characters, very long queries
5. **Accessibility** - Screen reader compatibility, keyboard navigation
### Browser Compatibility
- **Modern browsers** with ES modules support
- **CSS custom properties** support required
- **requestAnimationFrame** API required
## Maintenance Notes
### Code Organization
- **Single responsibility** - EventFilterManager handles only filtering
- **Event-driven** - Loose coupling via EventBus
- **CSS-first** - Visual logic in stylesheets, not JavaScript
- **Type-safe** - Full TypeScript implementation
### Common Issues
- **Timing**: Ensure EventFilterManager initializes after DOM ready
- **Event data**: Verify EVENTS_RENDERED events are emitted correctly
- **CSS specificity**: Filter styles must override existing event styles
- **Memory leaks**: Properly clean up event listeners in destroy()
This fuzzy search filter system provides an intuitive and performant way for users to quickly locate specific events within the calendar interface.