advanced-filter-system 1.5.2 → 1.7.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 +174 -518
- package/dist/afs.legacy.js +1 -1
- package/dist/afs.legacy.js.map +1 -1
- package/dist/afs.modern.js +1 -1
- package/dist/afs.modern.js.map +1 -1
- package/package.json +6 -8
package/README.md
CHANGED
|
@@ -1,627 +1,283 @@
|
|
|
1
1
|
# Advanced Filter System (AFS)
|
|
2
2
|
|
|
3
|
-
A
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
[Live Demo](https://misits.github.io/advanced-filter-system) | [NPM Package](https://www.npmjs.com/package/advanced-filter-system) | [Interactive Examples](examples/demo.html)
|
|
8
|
-
|
|
9
|
-
## Table of Contents
|
|
10
|
-
|
|
11
|
-
- [Advanced Filter System (AFS)](#advanced-filter-system-afs)
|
|
12
|
-
- [Table of Contents](#table-of-contents)
|
|
13
|
-
- [Features](#features)
|
|
14
|
-
- [Installation](#installation)
|
|
15
|
-
- [Quick Start](#quick-start)
|
|
16
|
-
- [HTML Structure](#html-structure)
|
|
17
|
-
- [JavaScript Initialization](#javascript-initialization)
|
|
18
|
-
- [Filter Logic Modes](#filter-logic-modes)
|
|
19
|
-
- [Mixed Mode (Recommended)](#mixed-mode-recommended)
|
|
20
|
-
- [Per-Type Logic Configuration](#per-type-logic-configuration)
|
|
21
|
-
- [Legacy Modes](#legacy-modes)
|
|
22
|
-
- [Filter Types & UI Components](#filter-types--ui-components)
|
|
23
|
-
- [Button Filters](#button-filters)
|
|
24
|
-
- [Select Dropdowns](#select-dropdowns)
|
|
25
|
-
- [Radio Buttons](#radio-buttons)
|
|
26
|
-
- [Checkboxes](#checkboxes)
|
|
27
|
-
- [Range Sliders](#range-sliders)
|
|
28
|
-
- [Date Range Filters](#date-range-filters)
|
|
29
|
-
- [Advanced Features](#advanced-features)
|
|
30
|
-
- [Search & Filtering](#search--filtering)
|
|
31
|
-
- [Sorting](#sorting)
|
|
32
|
-
- [Pagination](#pagination)
|
|
33
|
-
- [URL State Management](#url-state-management)
|
|
34
|
-
- [Animations](#animations)
|
|
35
|
-
- [Configuration Options](#configuration-options)
|
|
36
|
-
- [API Reference](#api-reference)
|
|
37
|
-
- [Examples](#examples)
|
|
38
|
-
- [Browser Support](#browser-support)
|
|
39
|
-
- [TypeScript Support](#typescript-support)
|
|
40
|
-
- [Contributing](#contributing)
|
|
41
|
-
- [License](#license)
|
|
3
|
+
A flexible, dependency-free JavaScript library for filtering DOM elements — with search, sorting, range filters, pagination and URL state built in.
|
|
4
|
+
|
|
5
|
+
[Live Demo](https://misits.github.io/advanced-filter-system) · [NPM](https://www.npmjs.com/package/advanced-filter-system) · [Documentation](docs/README.md)
|
|
42
6
|
|
|
43
7
|
## Features
|
|
44
8
|
|
|
45
|
-
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
- Radio buttons (exclusive)
|
|
54
|
-
- Checkboxes (multi-select)
|
|
55
|
-
- Range sliders with histograms
|
|
56
|
-
- Date range filters
|
|
57
|
-
- 🔎 **Smart Search**
|
|
58
|
-
- Real-time fuzzy search
|
|
59
|
-
- Multiple searchable fields
|
|
60
|
-
- Configurable debouncing
|
|
61
|
-
- Minimum character threshold
|
|
62
|
-
- ↕️ **Flexible Sorting**
|
|
63
|
-
- Multi-column sorting
|
|
64
|
-
- Custom sort functions
|
|
65
|
-
- Auto-detect data types
|
|
66
|
-
- Sort direction indicators
|
|
67
|
-
- 📄 **Advanced Pagination**
|
|
68
|
-
- Dynamic page sizes
|
|
69
|
-
- Smooth transitions
|
|
70
|
-
- Scroll-to-top option
|
|
71
|
-
- Custom pagination controls
|
|
72
|
-
- 🎨 **Rich Animations**
|
|
73
|
-
- 14+ animation types (fade, slide, scale, flip, etc.)
|
|
74
|
-
- Hardware-accelerated transitions
|
|
75
|
-
- Customizable duration and easing
|
|
76
|
-
- 🔗 **State Management**
|
|
77
|
-
- URL state persistence
|
|
78
|
-
- Browser history support
|
|
79
|
-
- Shareable filtered URLs
|
|
80
|
-
- State import/export
|
|
81
|
-
- ⚡ **Performance Optimized**
|
|
82
|
-
- Debounced updates
|
|
83
|
-
- Efficient DOM manipulation
|
|
84
|
-
- Minimal reflows and repaints
|
|
85
|
-
- 🎯 **Event System**
|
|
86
|
-
- Comprehensive event API
|
|
87
|
-
- Custom event support
|
|
88
|
-
- Debug mode with logging
|
|
9
|
+
- **Filtering** — buttons, checkboxes, radios and dropdowns, with OR / AND / mixed logic configurable per filter type
|
|
10
|
+
- **Search** — debounced text search across any data attributes, with optional match highlighting
|
|
11
|
+
- **Sorting** — by any data attribute (numbers, dates, strings auto-detected), multi-criteria, custom comparators, shuffle
|
|
12
|
+
- **Range filters** — draggable sliders (with optional histogram), min/max number inputs, date ranges
|
|
13
|
+
- **Pagination** — page controls, items-per-page, smooth scroll-to-top, fully aware of active filters and sort order
|
|
14
|
+
- **URL state** — the full filter state lives in the URL: shareable links, back/forward navigation, restored on load
|
|
15
|
+
- **Animations** — fade, slide, scale, flip, rotate, zoom, bounce, blur and more
|
|
16
|
+
- **TypeScript** — complete type definitions included
|
|
89
17
|
|
|
90
18
|
## Installation
|
|
91
19
|
|
|
92
20
|
```bash
|
|
93
|
-
# NPM
|
|
94
21
|
npm install advanced-filter-system
|
|
95
|
-
|
|
96
|
-
# Yarn
|
|
97
|
-
yarn add advanced-filter-system
|
|
98
|
-
|
|
99
|
-
# PNPM
|
|
100
|
-
pnpm add advanced-filter-system
|
|
101
22
|
```
|
|
102
23
|
|
|
103
|
-
Or
|
|
24
|
+
Or via CDN:
|
|
104
25
|
|
|
105
26
|
```html
|
|
106
27
|
<script type="module">
|
|
107
|
-
|
|
28
|
+
import { AFS } from 'https://unpkg.com/advanced-filter-system@latest/dist/afs.modern.js';
|
|
108
29
|
</script>
|
|
109
30
|
```
|
|
110
31
|
|
|
111
|
-
## Quick
|
|
32
|
+
## Quick start
|
|
112
33
|
|
|
113
|
-
|
|
34
|
+
A minimal, complete setup — filter buttons, search, counter and pagination:
|
|
114
35
|
|
|
115
36
|
```html
|
|
116
|
-
|
|
117
|
-
<
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
data-title="MacBook Pro"
|
|
140
|
-
data-price="2499"
|
|
141
|
-
data-date="2024-03-15">
|
|
142
|
-
<h3>MacBook Pro</h3>
|
|
143
|
-
<p>$2,499</p>
|
|
144
|
-
</div>
|
|
145
|
-
<!-- More items... -->
|
|
146
|
-
</div>
|
|
147
|
-
|
|
148
|
-
<!-- Pagination Container -->
|
|
149
|
-
<div class="afs-pagination-container"></div>
|
|
150
|
-
</body>
|
|
151
|
-
</html>
|
|
37
|
+
<!-- Filter controls -->
|
|
38
|
+
<button class="btn-filter" data-filter="*">All</button>
|
|
39
|
+
<button class="btn-filter" data-filter="category:tech">Tech</button>
|
|
40
|
+
<button class="btn-filter" data-filter="category:design">Design</button>
|
|
41
|
+
|
|
42
|
+
<!-- Search and counter -->
|
|
43
|
+
<input type="text" class="filter-search" placeholder="Search…">
|
|
44
|
+
<div class="filter-counter"></div>
|
|
45
|
+
|
|
46
|
+
<!-- Items: data-categories holds space-separated "type:value" pairs -->
|
|
47
|
+
<div class="items-container">
|
|
48
|
+
<div class="filter-item" data-categories="category:tech brand:apple"
|
|
49
|
+
data-title="MacBook Pro" data-price="2499">
|
|
50
|
+
MacBook Pro — $2,499
|
|
51
|
+
</div>
|
|
52
|
+
<div class="filter-item" data-categories="category:design brand:moleskine"
|
|
53
|
+
data-title="Sketchbook" data-price="29">
|
|
54
|
+
Sketchbook — $29
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<!-- Pagination controls are rendered in here -->
|
|
59
|
+
<div class="afs-pagination-container"></div>
|
|
152
60
|
```
|
|
153
61
|
|
|
154
|
-
### JavaScript Initialization
|
|
155
|
-
|
|
156
62
|
```javascript
|
|
157
63
|
import { AFS } from 'advanced-filter-system';
|
|
158
64
|
|
|
159
65
|
const afs = new AFS({
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
searchKeys: ['title', 'categories'],
|
|
169
|
-
|
|
170
|
-
// NEW: Advanced filter logic
|
|
171
|
-
filterCategoryMode: 'mixed', // OR within categories, AND between
|
|
172
|
-
filterTypeLogic: {
|
|
173
|
-
category: { mode: 'OR', multi: true }, // Multi-select OR
|
|
174
|
-
brand: 'OR', // Toggle mode
|
|
175
|
-
price: 'AND' // Multi-select AND
|
|
176
|
-
},
|
|
177
|
-
|
|
178
|
-
// Pagination
|
|
179
|
-
pagination: {
|
|
180
|
-
enabled: true,
|
|
181
|
-
itemsPerPage: 12
|
|
182
|
-
},
|
|
183
|
-
|
|
184
|
-
// Animations
|
|
185
|
-
animation: {
|
|
186
|
-
type: 'fade',
|
|
187
|
-
duration: 300
|
|
188
|
-
},
|
|
189
|
-
|
|
190
|
-
// Debug mode
|
|
191
|
-
debug: true
|
|
66
|
+
containerSelector: '.items-container', // required
|
|
67
|
+
itemSelector: '.filter-item', // required
|
|
68
|
+
filterButtonSelector: '.btn-filter',
|
|
69
|
+
searchInputSelector: '.filter-search',
|
|
70
|
+
counterSelector: '.filter-counter',
|
|
71
|
+
searchKeys: ['title', 'categories'],
|
|
72
|
+
pagination: { enabled: true, itemsPerPage: 12 },
|
|
73
|
+
animation: { type: 'fade', duration: 300 },
|
|
192
74
|
});
|
|
193
75
|
```
|
|
194
76
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
The most intuitive filtering experience - OR logic within filter categories, AND logic between different categories.
|
|
200
|
-
|
|
201
|
-
```javascript
|
|
202
|
-
const afs = new AFS({
|
|
203
|
-
filterCategoryMode: 'mixed',
|
|
204
|
-
// When user selects: Tech OR Design AND Apple OR Samsung
|
|
205
|
-
// Shows: (Tech OR Design) AND (Apple OR Samsung)
|
|
206
|
-
});
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
### Per-Type Logic Configuration
|
|
210
|
-
|
|
211
|
-
Configure each filter type independently for maximum flexibility.
|
|
212
|
-
|
|
213
|
-
```javascript
|
|
214
|
-
const afs = new AFS({
|
|
215
|
-
filterCategoryMode: 'mixed',
|
|
216
|
-
filterTypeLogic: {
|
|
217
|
-
category: { mode: 'OR', multi: true }, // Multi-select checkboxes
|
|
218
|
-
brand: 'OR', // Toggle buttons (exclusive)
|
|
219
|
-
price: 'AND', // Multi-select with AND logic
|
|
220
|
-
features: { mode: 'OR', multi: true } // Multi-select with OR logic
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
// Update logic at runtime
|
|
225
|
-
afs.filter.setFilterTypeLogic('brand', { mode: 'OR', multi: true });
|
|
77
|
+
```css
|
|
78
|
+
/* AFS toggles these two classes — style them however you like */
|
|
79
|
+
.btn-filter.active { background: #000; color: #fff; }
|
|
80
|
+
.filter-item.hidden { display: none !important; }
|
|
226
81
|
```
|
|
227
82
|
|
|
228
|
-
|
|
83
|
+
That's it. Clicking a filter button, typing in the search box or changing pages all update the items, the counter and the URL.
|
|
229
84
|
|
|
230
|
-
|
|
231
|
-
// Legacy OR mode (all filters use OR logic)
|
|
232
|
-
const afs = new AFS({ filterCategoryMode: 'OR' });
|
|
85
|
+
## How filtering works
|
|
233
86
|
|
|
234
|
-
|
|
235
|
-
const afs = new AFS({ filterCategoryMode: 'AND' });
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
## Filter Types & UI Components
|
|
239
|
-
|
|
240
|
-
### Button Filters
|
|
87
|
+
Every item declares its facets in `data-categories`, as space-separated `type:value` pairs:
|
|
241
88
|
|
|
242
89
|
```html
|
|
243
|
-
|
|
244
|
-
<button class="btn-filter" data-filter="category:tech">Technology</button>
|
|
245
|
-
|
|
246
|
-
<!-- Multi-select mode -->
|
|
247
|
-
<button class="btn-filter" data-filter="brand:apple">Apple</button>
|
|
248
|
-
<button class="btn-filter" data-filter="brand:samsung">Samsung</button>
|
|
249
|
-
|
|
250
|
-
<!-- Clear specific category -->
|
|
251
|
-
<button class="btn-filter" data-filter="category:*">Clear Categories</button>
|
|
90
|
+
<div class="filter-item" data-categories="category:tech brand:apple color:silver">
|
|
252
91
|
```
|
|
253
92
|
|
|
254
|
-
|
|
93
|
+
Filter controls target those pairs through `data-filter`:
|
|
255
94
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
</select>
|
|
262
|
-
```
|
|
95
|
+
| `data-filter` value | Meaning |
|
|
96
|
+
|---|---|
|
|
97
|
+
| `category:tech` | Toggle this filter |
|
|
98
|
+
| `*` | Reset — show everything |
|
|
99
|
+
| `category:*` | Clear every active `category:` filter |
|
|
263
100
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
```html
|
|
267
|
-
<label><input type="radio" name="category" class="btn-filter" data-filter="*" checked> All</label>
|
|
268
|
-
<label><input type="radio" name="category" class="btn-filter" data-filter="category:tech"> Tech</label>
|
|
269
|
-
<label><input type="radio" name="category" class="btn-filter" data-filter="category:design"> Design</label>
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
### Checkboxes
|
|
273
|
-
|
|
274
|
-
```html
|
|
275
|
-
<label><input type="checkbox" class="btn-filter" data-filter="category:tech"> Technology</label>
|
|
276
|
-
<label><input type="checkbox" class="btn-filter" data-filter="category:design"> Design</label>
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
### Range Sliders
|
|
101
|
+
By default AFS runs in **mixed mode**: filters of the same type combine with OR, different types combine with AND. Selecting *Tech*, *Design* and *Apple* shows items that are `(tech OR design) AND apple`. Each type's logic is configurable:
|
|
280
102
|
|
|
281
103
|
```javascript
|
|
282
|
-
// Add price range slider with histogram
|
|
283
|
-
afs.rangeFilter.addRangeSlider({
|
|
284
|
-
key: 'price',
|
|
285
|
-
type: 'number',
|
|
286
|
-
container: '.price-range-container',
|
|
287
|
-
min: 0,
|
|
288
|
-
max: 3000,
|
|
289
|
-
step: 50,
|
|
290
|
-
ui: {
|
|
291
|
-
showHistogram: true,
|
|
292
|
-
bins: 10
|
|
293
|
-
}
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
// Add rating range slider
|
|
297
|
-
afs.rangeFilter.addRangeSlider({
|
|
298
|
-
key: 'rating',
|
|
299
|
-
type: 'number',
|
|
300
|
-
container: '.rating-range-container',
|
|
301
|
-
min: 4.0,
|
|
302
|
-
max: 5.0,
|
|
303
|
-
step: 0.1
|
|
304
|
-
});
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
### Date Range Filters
|
|
308
|
-
|
|
309
|
-
```javascript
|
|
310
|
-
// Add date range filter
|
|
311
|
-
afs.dateFilter.addDateRange({
|
|
312
|
-
key: 'date',
|
|
313
|
-
container: '.date-range-container',
|
|
314
|
-
minDate: new Date('2024-01-01'),
|
|
315
|
-
maxDate: new Date(),
|
|
316
|
-
format: 'YYYY-MM-DD'
|
|
317
|
-
});
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
## Advanced Features
|
|
321
|
-
|
|
322
|
-
### Search & Filtering
|
|
323
|
-
|
|
324
|
-
```javascript
|
|
325
|
-
// Programmatic search
|
|
326
|
-
afs.search.search('query');
|
|
327
|
-
afs.search.clearSearch();
|
|
328
|
-
afs.search.setValue('new query');
|
|
329
|
-
|
|
330
|
-
// Programmatic filtering
|
|
331
|
-
afs.filter.addFilter('category:tech');
|
|
332
|
-
afs.filter.removeFilter('category:tech');
|
|
333
|
-
afs.filter.clearAllFilters();
|
|
334
|
-
afs.filter.clearFilterCategory('category:*');
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
### Sorting
|
|
338
|
-
|
|
339
|
-
```javascript
|
|
340
|
-
// Sort by single field
|
|
341
|
-
afs.sort.sort('price', 'desc');
|
|
342
|
-
|
|
343
|
-
// Custom sorting
|
|
344
|
-
afs.sort.sortWithComparator('title', (a, b) => {
|
|
345
|
-
return a.localeCompare(b, 'en', { numeric: true });
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
// Shuffle items
|
|
349
|
-
afs.sort.shuffle();
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
### Pagination
|
|
353
|
-
|
|
354
|
-
```javascript
|
|
355
|
-
// Pagination navigation
|
|
356
|
-
afs.pagination.goToPage(2);
|
|
357
|
-
afs.pagination.nextPage();
|
|
358
|
-
afs.pagination.previousPage();
|
|
359
|
-
|
|
360
|
-
// Toggle pagination mode
|
|
361
|
-
afs.pagination.setPaginationMode(true); // Enable
|
|
362
|
-
afs.pagination.setPaginationMode(false); // Show all
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
### URL State Management
|
|
366
|
-
|
|
367
|
-
```javascript
|
|
368
|
-
// Enable URL state persistence
|
|
369
104
|
const afs = new AFS({
|
|
370
|
-
|
|
371
|
-
|
|
105
|
+
filterCategoryMode: 'mixed',
|
|
106
|
+
filterTypeLogic: {
|
|
107
|
+
category: { mode: 'OR', multi: true }, // multi-select (checkbox-style)
|
|
108
|
+
brand: 'OR', // exclusive (one at a time)
|
|
109
|
+
tags: 'AND', // items must match all selected
|
|
110
|
+
},
|
|
372
111
|
});
|
|
373
|
-
|
|
374
|
-
// Manual state management
|
|
375
|
-
const state = afs.getState();
|
|
376
|
-
afs.setState(state);
|
|
377
112
|
```
|
|
378
113
|
|
|
379
|
-
|
|
114
|
+
Buttons, checkboxes (`<input type="checkbox" data-filter>`), radios (`<input type="radio" data-filter>`) and dropdowns (`<select data-filter-type>`) are all supported — see the [Filter documentation](docs/filter.md).
|
|
380
115
|
|
|
381
|
-
|
|
382
|
-
const afs = new AFS({
|
|
383
|
-
animation: {
|
|
384
|
-
type: 'fade', // fade, slide, scale, flip, rotate, zoom, bounce, blur, etc.
|
|
385
|
-
duration: 400,
|
|
386
|
-
easing: 'ease-out'
|
|
387
|
-
}
|
|
388
|
-
});
|
|
116
|
+
## Documentation
|
|
389
117
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
118
|
+
| Module | Covers |
|
|
119
|
+
|---|---|
|
|
120
|
+
| [Filter](docs/filter.md) | Buttons, checkboxes, radios, dropdowns, logic modes, filter groups |
|
|
121
|
+
| [Search](docs/search.md) | Text search, debouncing, highlighting |
|
|
122
|
+
| [Sort](docs/sort.md) | Sort buttons, multi-criteria, custom comparators, shuffle |
|
|
123
|
+
| [Pagination](docs/pagination.md) | Page controls, items-per-page, scroll-to-top |
|
|
124
|
+
| [Range Filter](docs/range-filter.md) | Slider with optional histogram (numbers or dates) |
|
|
125
|
+
| [Input Range Filter](docs/input-range-filter.md) | Min/max number inputs |
|
|
126
|
+
| [Date Filter](docs/date-filter.md) | Date range pickers |
|
|
127
|
+
| [URL Manager](docs/url-manager.md) | URL parameters, shareable state, history |
|
|
128
|
+
|
|
129
|
+
## Common options
|
|
398
130
|
|
|
399
|
-
|
|
131
|
+
All options with their defaults live in [`src/core/Options.js`](src/core/Options.js). The ones you'll touch most:
|
|
400
132
|
|
|
401
133
|
```javascript
|
|
402
134
|
const afs = new AFS({
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
stateExpiry: 86400000, // 24 hours
|
|
451
|
-
observeDOM: false,
|
|
452
|
-
|
|
453
|
-
// CSS Classes
|
|
454
|
-
activeClass: 'active',
|
|
455
|
-
hiddenClass: 'hidden',
|
|
456
|
-
activeSortClass: 'sort-active',
|
|
457
|
-
|
|
458
|
-
// Debug mode
|
|
459
|
-
debug: true
|
|
135
|
+
// Selectors (containerSelector and itemSelector are required)
|
|
136
|
+
containerSelector: '.afs-filter-container',
|
|
137
|
+
itemSelector: '.afs-filter-item',
|
|
138
|
+
filterButtonSelector: '.afs-btn-filter',
|
|
139
|
+
filterDropdownSelector: '.afs-filter-dropdown',
|
|
140
|
+
searchInputSelector: '.afs-filter-search',
|
|
141
|
+
counterSelector: '.afs-filter-counter',
|
|
142
|
+
sortButtonSelector: '.afs-btn-sort',
|
|
143
|
+
|
|
144
|
+
// CSS classes AFS toggles
|
|
145
|
+
activeClass: 'active',
|
|
146
|
+
hiddenClass: 'hidden',
|
|
147
|
+
activeSortClass: 'sort-active',
|
|
148
|
+
|
|
149
|
+
// Filter logic
|
|
150
|
+
filterCategoryMode: 'mixed', // 'mixed' | 'OR' | 'AND'
|
|
151
|
+
filterTypeLogic: {}, // per-type config, see above
|
|
152
|
+
|
|
153
|
+
// Search
|
|
154
|
+
searchKeys: ['title'],
|
|
155
|
+
debounceTime: 300,
|
|
156
|
+
|
|
157
|
+
// Pagination (disabled by default)
|
|
158
|
+
pagination: {
|
|
159
|
+
enabled: false,
|
|
160
|
+
itemsPerPage: 10,
|
|
161
|
+
container: '.afs-pagination-container',
|
|
162
|
+
showPrevNext: true,
|
|
163
|
+
scrollToTop: false, // scrolls back to the top of the items list
|
|
164
|
+
scrollOffset: 50,
|
|
165
|
+
scrollBehavior: 'smooth', // 'smooth' | 'auto'
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
// Counter
|
|
169
|
+
counter: {
|
|
170
|
+
template: 'Showing {visible} of {total}',
|
|
171
|
+
showFiltered: true,
|
|
172
|
+
filteredTemplate: '({filtered} filtered)',
|
|
173
|
+
noResultsTemplate: 'No items found',
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
// Animations
|
|
177
|
+
animation: { type: 'fade', duration: 300 },
|
|
178
|
+
|
|
179
|
+
// Misc
|
|
180
|
+
debug: false, // log to console
|
|
181
|
+
preserveState: false, // persist state in sessionStorage across tab switches
|
|
460
182
|
});
|
|
461
183
|
```
|
|
462
184
|
|
|
463
|
-
## API
|
|
185
|
+
## API at a glance
|
|
464
186
|
|
|
465
|
-
|
|
187
|
+
Each feature lives on the instance: `afs.filter`, `afs.search`, `afs.sort`, `afs.pagination`, `afs.rangeFilter`, `afs.inputRangeFilter`, `afs.dateFilter`, `afs.urlManager`.
|
|
466
188
|
|
|
467
189
|
```javascript
|
|
468
|
-
//
|
|
190
|
+
// Filtering
|
|
469
191
|
afs.filter.addFilter('category:tech');
|
|
470
192
|
afs.filter.removeFilter('category:tech');
|
|
471
|
-
afs.filter.clearAllFilters();
|
|
472
|
-
afs.filter.clearFilterCategory('category:*');
|
|
473
|
-
afs.filter.setFilterTypeLogic('brand', { mode: 'OR', multi: true });
|
|
474
|
-
afs.filter.toggleFilterExclusive('category:tech');
|
|
193
|
+
afs.filter.clearAllFilters(); // filters + search + dropdowns + checkboxes
|
|
475
194
|
|
|
476
195
|
// Search
|
|
477
|
-
afs.search.
|
|
196
|
+
afs.search.setValue('macbook');
|
|
478
197
|
afs.search.clearSearch();
|
|
479
|
-
afs.search.setValue('new query');
|
|
480
|
-
const currentQuery = afs.search.getValue();
|
|
481
198
|
|
|
482
|
-
// Sorting
|
|
199
|
+
// Sorting
|
|
483
200
|
afs.sort.sort('price', 'desc');
|
|
484
|
-
afs.sort.sortMultiple([
|
|
485
|
-
{ key: 'category', direction: 'asc' },
|
|
486
|
-
{ key: 'price', direction: 'desc' }
|
|
487
|
-
]);
|
|
488
201
|
afs.sort.shuffle();
|
|
489
202
|
afs.sort.reset();
|
|
490
203
|
|
|
491
204
|
// Pagination
|
|
492
205
|
afs.pagination.goToPage(2);
|
|
493
206
|
afs.pagination.nextPage();
|
|
494
|
-
afs.pagination.
|
|
495
|
-
afs.pagination.
|
|
207
|
+
afs.pagination.setItemsPerPage(24);
|
|
208
|
+
afs.pagination.getPageInfo(); // { currentPage, itemsPerPage, totalPages }
|
|
496
209
|
|
|
497
|
-
// Range
|
|
210
|
+
// Range widgets (containers are DOM elements)
|
|
498
211
|
afs.rangeFilter.addRangeSlider({
|
|
499
|
-
|
|
500
|
-
|
|
212
|
+
key: 'price', type: 'number',
|
|
213
|
+
container: document.querySelector('.price-slider'),
|
|
214
|
+
min: 0, max: 1000, step: 10,
|
|
215
|
+
ui: { showHistogram: true, bins: 12 },
|
|
501
216
|
});
|
|
217
|
+
afs.inputRangeFilter.addInputRange({ key: 'rating', container: el, min: 0, max: 5, step: 0.5 });
|
|
218
|
+
afs.dateFilter.addDateRange({ key: 'date', container: el });
|
|
502
219
|
|
|
503
|
-
//
|
|
504
|
-
afs.
|
|
505
|
-
|
|
506
|
-
container: '.date-range-container'
|
|
507
|
-
});
|
|
508
|
-
|
|
509
|
-
// State
|
|
510
|
-
const state = afs.getState();
|
|
511
|
-
afs.setState(state);
|
|
512
|
-
|
|
513
|
-
// Events
|
|
514
|
-
afs.on('filtersApplied', (data) => {
|
|
515
|
-
console.log(`Showing ${data.visibleItems} of ${data.total} items`);
|
|
516
|
-
});
|
|
220
|
+
// Lifecycle
|
|
221
|
+
afs.refresh(); // re-scan items (after DOM changes)
|
|
222
|
+
afs.destroy();
|
|
517
223
|
```
|
|
518
224
|
|
|
519
|
-
###
|
|
225
|
+
### Events
|
|
520
226
|
|
|
521
227
|
```javascript
|
|
522
|
-
|
|
523
|
-
afs.on('
|
|
524
|
-
afs.on('
|
|
525
|
-
afs.on('
|
|
526
|
-
afs.on('
|
|
527
|
-
afs.on('urlStateLoaded',
|
|
228
|
+
afs.on('filtersApplied', ({ activeFilters, visibleItems }) => { /* … */ });
|
|
229
|
+
afs.on('search', ({ query, matches, total }) => { /* … */ });
|
|
230
|
+
afs.on('sort', ({ key, direction }) => { /* … */ });
|
|
231
|
+
afs.on('pageChanged', ({ currentPage, totalPages }) => { /* … */ });
|
|
232
|
+
afs.on('filtersCleared', () => { /* … */ });
|
|
233
|
+
afs.on('urlStateLoaded', ({ params }) => { /* … */ });
|
|
528
234
|
```
|
|
529
235
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
The project includes comprehensive examples demonstrating all features:
|
|
533
|
-
|
|
534
|
-
- **[Interactive Demo](examples/demo.html)** - Complete demo with all filter types
|
|
535
|
-
- **[Button Filters](examples/demo.html#buttons)** - Toggle and multi-select buttons
|
|
536
|
-
- **[Select Dropdowns](examples/demo.html#select)** - Dropdown filter controls
|
|
537
|
-
- **[Radio Buttons](examples/demo.html#radio)** - Exclusive radio button filters
|
|
538
|
-
- **[Checkboxes](examples/demo.html#checkbox)** - Multi-select checkbox filters
|
|
539
|
-
- **[Range Filters](examples/demo.html#range)** - Sliders with histogram support
|
|
540
|
-
- **[Search Functionality](examples/demo.html#search)** - Real-time search examples
|
|
236
|
+
`on`, `once`, `off`, `removeAllListeners` are available. Each module's documentation lists its events and payloads.
|
|
541
237
|
|
|
542
|
-
|
|
238
|
+
## TypeScript
|
|
543
239
|
|
|
544
|
-
|
|
545
|
-
# Clone the repository
|
|
546
|
-
git clone https://github.com/misits/advanced-filter-system.git
|
|
547
|
-
cd advanced-filter-system
|
|
548
|
-
|
|
549
|
-
# Open examples in browser
|
|
550
|
-
open examples/index.html
|
|
551
|
-
```
|
|
552
|
-
|
|
553
|
-
## Browser Support
|
|
554
|
-
|
|
555
|
-
- Chrome (latest)
|
|
556
|
-
- Firefox (latest)
|
|
557
|
-
- Safari (latest)
|
|
558
|
-
- Edge (latest)
|
|
559
|
-
- Opera (latest)
|
|
560
|
-
|
|
561
|
-
Modern browser features used:
|
|
562
|
-
- ES6 Modules
|
|
563
|
-
- CSS Custom Properties
|
|
564
|
-
- IntersectionObserver API
|
|
565
|
-
- URLSearchParams API
|
|
566
|
-
|
|
567
|
-
## TypeScript Support
|
|
568
|
-
|
|
569
|
-
Full TypeScript support with comprehensive type definitions:
|
|
240
|
+
Type definitions ship with the package:
|
|
570
241
|
|
|
571
242
|
```typescript
|
|
572
243
|
import { AFS, AFSOptions, FilterTypeLogic } from 'advanced-filter-system';
|
|
573
244
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
const filterLogic: FilterTypeLogic = {
|
|
579
|
-
category: { mode: 'OR', multi: true },
|
|
580
|
-
brand: 'OR'
|
|
245
|
+
const logic: FilterTypeLogic = {
|
|
246
|
+
category: { mode: 'OR', multi: true },
|
|
247
|
+
brand: 'OR',
|
|
581
248
|
};
|
|
582
249
|
|
|
583
250
|
const afs = new AFS({
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
}
|
|
251
|
+
containerSelector: '#items',
|
|
252
|
+
itemSelector: '.item',
|
|
253
|
+
filterTypeLogic: logic,
|
|
254
|
+
});
|
|
588
255
|
```
|
|
589
256
|
|
|
590
|
-
##
|
|
257
|
+
## Browser support
|
|
591
258
|
|
|
592
|
-
|
|
259
|
+
Modern evergreen browsers (Chrome, Firefox, Safari, Edge). Uses ES modules, `URLSearchParams` and the History API. `dist/afs.legacy.js` (UMD) is provided for non-module environments.
|
|
593
260
|
|
|
594
|
-
|
|
595
|
-
2. Code style and standards
|
|
596
|
-
3. Testing requirements
|
|
597
|
-
4. Pull request process
|
|
598
|
-
5. Bug reporting guidelines
|
|
599
|
-
6. Feature request templates
|
|
600
|
-
|
|
601
|
-
### Development Setup
|
|
261
|
+
## Development
|
|
602
262
|
|
|
603
263
|
```bash
|
|
604
|
-
# Clone and install
|
|
605
264
|
git clone https://github.com/misits/advanced-filter-system.git
|
|
606
265
|
cd advanced-filter-system
|
|
607
266
|
npm install
|
|
608
267
|
|
|
609
|
-
#
|
|
610
|
-
npm run
|
|
611
|
-
|
|
612
|
-
# Build for production
|
|
613
|
-
npm run build
|
|
268
|
+
npm test # jest test suite
|
|
269
|
+
npm run build # build dist/ (development)
|
|
270
|
+
npm run build:prod # minified production build
|
|
614
271
|
|
|
615
|
-
#
|
|
616
|
-
npm
|
|
272
|
+
# Try the demo (imports ../dist/afs.modern.js, so build first)
|
|
273
|
+
npm run build && npx serve .
|
|
274
|
+
# then open http://localhost:3000/examples/demo.html
|
|
617
275
|
```
|
|
618
276
|
|
|
619
277
|
## License
|
|
620
278
|
|
|
621
|
-
|
|
279
|
+
MIT — see [LICENSE](LICENSE).
|
|
622
280
|
|
|
623
281
|
---
|
|
624
282
|
|
|
625
283
|
Made with ♥ by [misits](https://github.com/misits)
|
|
626
|
-
|
|
627
|
-
**Star ⭐ this repo if you find it helpful!**
|