Implements a fuzzy search filter system using Fuse.js to enhance event searching. This system allows users to quickly find events by typing partial matches of event titles or descriptions, providing visual feedback by dimming non-matching events. The filter persists during navigation and includes escape key support for quick clearing. It also includes performance optimizations like requestAnimationFrame debouncing.
6.7 KiB
6.7 KiB
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
/* 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_CHANGEDevents - NavigationRenderer applies filter state to all grid containers
- Ensures filter persists when navigating between time periods
Event Flow
- User Input → Search field receives input
- Debounced Processing → RequestAnimationFrame prevents excessive filtering
- Fuzzy Search → Fuse.js performs search against event titles/descriptions
- DOM Updates → Matching events marked with
data-matches="true" - CSS Application → Non-matching events automatically dimmed via CSS rules
- Cross-Grid Sync → Filter applied to all pre-rendered grids
Configuration
Fuse.js Settings
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
:root {
--filter-dimmed-opacity: 0.2; /* Opacity for non-matching events */
--filter-transition: 200ms ease; /* Smooth opacity transitions */
}
Integration Points
CalendarManager
// EventFilterManager is initialized in CalendarManager constructor
this.eventFilterManager = new EventFilterManager();
EventRenderer
// Events emit EVENTS_RENDERED for filter system to track
this.eventBus.emit(CoreEvents.EVENTS_RENDERED, {
events: events,
container: context.container
});
HTML Structure
<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
- RequestAnimationFrame debouncing prevents excessive search operations
- CSS-based visual updates leverage browser's rendering pipeline
- Event delegation avoids per-event listener overhead
- 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
- Basic search functionality - Verify fuzzy matching works
- Performance testing - Large event sets (1000+ events)
- Cross-navigation - Filter persistence during navigation
- Edge cases - Empty results, special characters, very long queries
- 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.