advanced-filter-system 1.5.1 → 1.6.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 +178 -505
- 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 +13 -9
- package/src/types/core.d.ts +65 -0
- package/src/types/date-filter.ts +18 -0
- package/src/types/features.d.ts +148 -0
- package/src/types/filter.ts +17 -0
- package/src/types/index.d.ts +442 -0
- package/src/types/input-range-filter.ts +19 -0
- package/src/types/pagination.ts +37 -0
- package/src/types/range-filter.ts +8 -0
- package/src/types/search.ts +5 -0
- package/src/types/sort.ts +9 -0
- package/src/types/url-manager.ts +11 -0
- package/src/types/utils.d.ts +128 -0
package/README.md
CHANGED
|
@@ -1,610 +1,283 @@
|
|
|
1
1
|
# Advanced Filter System (AFS)
|
|
2
2
|
|
|
3
|
-
A
|
|
4
|
-
|
|
5
|
-
[Live Demo](https://misits.github.io/advanced-filter-system)
|
|
6
|
-
|
|
7
|
-
## Table of Contents
|
|
8
|
-
|
|
9
|
-
- [Advanced Filter System (AFS)](#advanced-filter-system-afs)
|
|
10
|
-
- [Table of Contents](#table-of-contents)
|
|
11
|
-
- [Features](#features)
|
|
12
|
-
- [Installation](#installation)
|
|
13
|
-
- [Quick Start](#quick-start)
|
|
14
|
-
- [HTML Structure](#html-structure)
|
|
15
|
-
- [JavaScript Initialization](#javascript-initialization)
|
|
16
|
-
- [Filter Logic Modes](#filter-logic-modes)
|
|
17
|
-
- [Mixed Mode (Recommended)](#mixed-mode-recommended)
|
|
18
|
-
- [Per-Type Logic Configuration](#per-type-logic-configuration)
|
|
19
|
-
- [Legacy Modes](#legacy-modes)
|
|
20
|
-
- [Filter Types & UI Components](#filter-types--ui-components)
|
|
21
|
-
- [Button Filters](#button-filters)
|
|
22
|
-
- [Select Dropdowns](#select-dropdowns)
|
|
23
|
-
- [Radio Buttons](#radio-buttons)
|
|
24
|
-
- [Checkboxes](#checkboxes)
|
|
25
|
-
- [Range Sliders](#range-sliders)
|
|
26
|
-
- [Date Range Filters](#date-range-filters)
|
|
27
|
-
- [Advanced Features](#advanced-features)
|
|
28
|
-
- [Search & Filtering](#search--filtering)
|
|
29
|
-
- [Sorting](#sorting)
|
|
30
|
-
- [Pagination](#pagination)
|
|
31
|
-
- [URL State Management](#url-state-management)
|
|
32
|
-
- [Animations](#animations)
|
|
33
|
-
- [Configuration Options](#configuration-options)
|
|
34
|
-
- [API Reference](#api-reference)
|
|
35
|
-
- [Examples](#examples)
|
|
36
|
-
- [Browser Support](#browser-support)
|
|
37
|
-
- [TypeScript Support](#typescript-support)
|
|
38
|
-
- [Contributing](#contributing)
|
|
39
|
-
- [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)
|
|
40
6
|
|
|
41
7
|
## Features
|
|
42
8
|
|
|
43
|
-
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
- Radio buttons (exclusive)
|
|
52
|
-
- Checkboxes (multi-select)
|
|
53
|
-
- Range sliders with histograms
|
|
54
|
-
- Date range filters
|
|
55
|
-
- 🔎 **Smart Search**
|
|
56
|
-
- Real-time fuzzy search
|
|
57
|
-
- Multiple searchable fields
|
|
58
|
-
- Configurable debouncing
|
|
59
|
-
- Minimum character threshold
|
|
60
|
-
- ↕️ **Flexible Sorting**
|
|
61
|
-
- Multi-column sorting
|
|
62
|
-
- Custom sort functions
|
|
63
|
-
- Auto-detect data types
|
|
64
|
-
- Sort direction indicators
|
|
65
|
-
- 📄 **Advanced Pagination**
|
|
66
|
-
- Dynamic page sizes
|
|
67
|
-
- Smooth transitions
|
|
68
|
-
- Scroll-to-top option
|
|
69
|
-
- Custom pagination controls
|
|
70
|
-
- 🎨 **Rich Animations**
|
|
71
|
-
- 14+ animation types (fade, slide, scale, flip, etc.)
|
|
72
|
-
- Hardware-accelerated transitions
|
|
73
|
-
- Customizable duration and easing
|
|
74
|
-
- 🔗 **State Management**
|
|
75
|
-
- URL state persistence
|
|
76
|
-
- Browser history support
|
|
77
|
-
- Shareable filtered URLs
|
|
78
|
-
- State import/export
|
|
79
|
-
- ⚡ **Performance Optimized**
|
|
80
|
-
- Debounced updates
|
|
81
|
-
- Efficient DOM manipulation
|
|
82
|
-
- Minimal reflows and repaints
|
|
83
|
-
- 🎯 **Event System**
|
|
84
|
-
- Comprehensive event API
|
|
85
|
-
- Custom event support
|
|
86
|
-
- 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
|
|
87
17
|
|
|
88
18
|
## Installation
|
|
89
19
|
|
|
90
20
|
```bash
|
|
91
|
-
# NPM
|
|
92
21
|
npm install advanced-filter-system
|
|
93
|
-
|
|
94
|
-
# Yarn
|
|
95
|
-
yarn add advanced-filter-system
|
|
96
|
-
|
|
97
|
-
# PNPM
|
|
98
|
-
pnpm add advanced-filter-system
|
|
99
22
|
```
|
|
100
23
|
|
|
101
|
-
Or
|
|
24
|
+
Or via CDN:
|
|
102
25
|
|
|
103
26
|
```html
|
|
104
27
|
<script type="module">
|
|
105
|
-
|
|
28
|
+
import { AFS } from 'https://unpkg.com/advanced-filter-system@latest/dist/afs.modern.js';
|
|
106
29
|
</script>
|
|
107
30
|
```
|
|
108
31
|
|
|
109
|
-
## Quick
|
|
32
|
+
## Quick start
|
|
110
33
|
|
|
111
|
-
|
|
34
|
+
A minimal, complete setup — filter buttons, search, counter and pagination:
|
|
112
35
|
|
|
113
36
|
```html
|
|
114
|
-
|
|
115
|
-
<
|
|
116
|
-
<
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
data-title="MacBook Pro"
|
|
138
|
-
data-price="2499"
|
|
139
|
-
data-date="2024-03-15">
|
|
140
|
-
<h3>MacBook Pro</h3>
|
|
141
|
-
<p>$2,499</p>
|
|
142
|
-
</div>
|
|
143
|
-
<!-- More items... -->
|
|
144
|
-
</div>
|
|
145
|
-
|
|
146
|
-
<!-- Pagination Container -->
|
|
147
|
-
<div class="afs-pagination-container"></div>
|
|
148
|
-
</body>
|
|
149
|
-
</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>
|
|
150
60
|
```
|
|
151
61
|
|
|
152
|
-
### JavaScript Initialization
|
|
153
|
-
|
|
154
62
|
```javascript
|
|
155
63
|
import { AFS } from 'advanced-filter-system';
|
|
156
64
|
|
|
157
65
|
const afs = new AFS({
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
searchKeys: ['title', 'categories'],
|
|
167
|
-
|
|
168
|
-
// NEW: Advanced filter logic
|
|
169
|
-
filterCategoryMode: 'mixed', // OR within categories, AND between
|
|
170
|
-
filterTypeLogic: {
|
|
171
|
-
category: { mode: 'OR', multi: true }, // Multi-select OR
|
|
172
|
-
brand: 'OR', // Toggle mode
|
|
173
|
-
price: 'AND' // Multi-select AND
|
|
174
|
-
},
|
|
175
|
-
|
|
176
|
-
// Pagination
|
|
177
|
-
pagination: {
|
|
178
|
-
enabled: true,
|
|
179
|
-
itemsPerPage: 12
|
|
180
|
-
},
|
|
181
|
-
|
|
182
|
-
// Animations
|
|
183
|
-
animation: {
|
|
184
|
-
type: 'fade',
|
|
185
|
-
duration: 300
|
|
186
|
-
},
|
|
187
|
-
|
|
188
|
-
// Debug mode
|
|
189
|
-
debug: true
|
|
190
|
-
});
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
## Filter Logic Modes
|
|
194
|
-
|
|
195
|
-
### Mixed Mode (Recommended)
|
|
196
|
-
|
|
197
|
-
The most intuitive filtering experience - OR logic within filter categories, AND logic between different categories.
|
|
198
|
-
|
|
199
|
-
```javascript
|
|
200
|
-
const afs = new AFS({
|
|
201
|
-
filterCategoryMode: 'mixed',
|
|
202
|
-
// When user selects: Tech OR Design AND Apple OR Samsung
|
|
203
|
-
// Shows: (Tech OR Design) AND (Apple OR Samsung)
|
|
204
|
-
});
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
### Per-Type Logic Configuration
|
|
208
|
-
|
|
209
|
-
Configure each filter type independently for maximum flexibility.
|
|
210
|
-
|
|
211
|
-
```javascript
|
|
212
|
-
const afs = new AFS({
|
|
213
|
-
filterCategoryMode: 'mixed',
|
|
214
|
-
filterTypeLogic: {
|
|
215
|
-
category: { mode: 'OR', multi: true }, // Multi-select checkboxes
|
|
216
|
-
brand: 'OR', // Toggle buttons (exclusive)
|
|
217
|
-
price: 'AND', // Multi-select with AND logic
|
|
218
|
-
features: { mode: 'OR', multi: true } // Multi-select with OR logic
|
|
219
|
-
}
|
|
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 },
|
|
220
74
|
});
|
|
221
|
-
|
|
222
|
-
// Update logic at runtime
|
|
223
|
-
afs.filter.setFilterTypeLogic('brand', { mode: 'OR', multi: true });
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
### Legacy Modes
|
|
227
|
-
|
|
228
|
-
```javascript
|
|
229
|
-
// Legacy OR mode (all filters use OR logic)
|
|
230
|
-
const afs = new AFS({ filterCategoryMode: 'OR' });
|
|
231
|
-
|
|
232
|
-
// Legacy AND mode (all filters use AND logic)
|
|
233
|
-
const afs = new AFS({ filterCategoryMode: 'AND' });
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
## Filter Types & UI Components
|
|
237
|
-
|
|
238
|
-
### Button Filters
|
|
239
|
-
|
|
240
|
-
```html
|
|
241
|
-
<!-- Toggle mode (exclusive) -->
|
|
242
|
-
<button class="btn-filter" data-filter="category:tech">Technology</button>
|
|
243
|
-
|
|
244
|
-
<!-- Multi-select mode -->
|
|
245
|
-
<button class="btn-filter" data-filter="brand:apple">Apple</button>
|
|
246
|
-
<button class="btn-filter" data-filter="brand:samsung">Samsung</button>
|
|
247
|
-
|
|
248
|
-
<!-- Clear specific category -->
|
|
249
|
-
<button class="btn-filter" data-filter="category:*">Clear Categories</button>
|
|
250
75
|
```
|
|
251
76
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
<option value="*">All Categories</option>
|
|
257
|
-
<option value="category:tech">Technology</option>
|
|
258
|
-
<option value="category:design">Design</option>
|
|
259
|
-
</select>
|
|
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; }
|
|
260
81
|
```
|
|
261
82
|
|
|
262
|
-
|
|
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.
|
|
263
84
|
|
|
264
|
-
|
|
265
|
-
<label><input type="radio" name="category" class="btn-filter" data-filter="*" checked> All</label>
|
|
266
|
-
<label><input type="radio" name="category" class="btn-filter" data-filter="category:tech"> Tech</label>
|
|
267
|
-
<label><input type="radio" name="category" class="btn-filter" data-filter="category:design"> Design</label>
|
|
268
|
-
```
|
|
85
|
+
## How filtering works
|
|
269
86
|
|
|
270
|
-
|
|
87
|
+
Every item declares its facets in `data-categories`, as space-separated `type:value` pairs:
|
|
271
88
|
|
|
272
89
|
```html
|
|
273
|
-
<
|
|
274
|
-
<label><input type="checkbox" class="btn-filter" data-filter="category:design"> Design</label>
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
### Range Sliders
|
|
278
|
-
|
|
279
|
-
```javascript
|
|
280
|
-
// Add price range slider with histogram
|
|
281
|
-
afs.rangeFilter.addRangeSlider({
|
|
282
|
-
key: 'price',
|
|
283
|
-
type: 'number',
|
|
284
|
-
container: '.price-range-container',
|
|
285
|
-
min: 0,
|
|
286
|
-
max: 3000,
|
|
287
|
-
step: 50,
|
|
288
|
-
ui: {
|
|
289
|
-
showHistogram: true,
|
|
290
|
-
bins: 10
|
|
291
|
-
}
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
// Add rating range slider
|
|
295
|
-
afs.rangeFilter.addRangeSlider({
|
|
296
|
-
key: 'rating',
|
|
297
|
-
type: 'number',
|
|
298
|
-
container: '.rating-range-container',
|
|
299
|
-
min: 4.0,
|
|
300
|
-
max: 5.0,
|
|
301
|
-
step: 0.1
|
|
302
|
-
});
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
### Date Range Filters
|
|
306
|
-
|
|
307
|
-
```javascript
|
|
308
|
-
// Add date range filter
|
|
309
|
-
afs.dateFilter.addDateRange({
|
|
310
|
-
key: 'date',
|
|
311
|
-
container: '.date-range-container',
|
|
312
|
-
minDate: new Date('2024-01-01'),
|
|
313
|
-
maxDate: new Date(),
|
|
314
|
-
format: 'YYYY-MM-DD'
|
|
315
|
-
});
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
## Advanced Features
|
|
319
|
-
|
|
320
|
-
### Search & Filtering
|
|
321
|
-
|
|
322
|
-
```javascript
|
|
323
|
-
// Configure search
|
|
324
|
-
afs.search.configure({
|
|
325
|
-
keys: ['title', 'description', 'categories'],
|
|
326
|
-
fuzzy: true,
|
|
327
|
-
minLength: 2,
|
|
328
|
-
debounce: 300
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
// Programmatic filtering
|
|
332
|
-
afs.filter.addFilter('category:tech');
|
|
333
|
-
afs.filter.removeFilter('category:tech');
|
|
334
|
-
afs.filter.clearAllFilters();
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
### Sorting
|
|
338
|
-
|
|
339
|
-
```javascript
|
|
340
|
-
// Sort by single field
|
|
341
|
-
afs.filter.sortWithOrder('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.filter.shuffle();
|
|
90
|
+
<div class="filter-item" data-categories="category:tech brand:apple color:silver">
|
|
350
91
|
```
|
|
351
92
|
|
|
352
|
-
|
|
93
|
+
Filter controls target those pairs through `data-filter`:
|
|
353
94
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
scrollToTop: true,
|
|
360
|
-
scrollBehavior: 'smooth'
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
// Toggle pagination mode
|
|
364
|
-
afs.pagination.setPaginationMode(true); // Enable
|
|
365
|
-
afs.pagination.setPaginationMode(false); // Show all
|
|
366
|
-
```
|
|
95
|
+
| `data-filter` value | Meaning |
|
|
96
|
+
|---|---|
|
|
97
|
+
| `category:tech` | Toggle this filter |
|
|
98
|
+
| `*` | Reset — show everything |
|
|
99
|
+
| `category:*` | Clear every active `category:` filter |
|
|
367
100
|
|
|
368
|
-
|
|
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:
|
|
369
102
|
|
|
370
103
|
```javascript
|
|
371
|
-
// Enable URL state persistence
|
|
372
104
|
const afs = new AFS({
|
|
373
|
-
|
|
374
|
-
|
|
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
|
+
},
|
|
375
111
|
});
|
|
376
|
-
|
|
377
|
-
// Manual state management
|
|
378
|
-
const state = afs.getState();
|
|
379
|
-
afs.setState(state);
|
|
380
112
|
```
|
|
381
113
|
|
|
382
|
-
|
|
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).
|
|
383
115
|
|
|
384
|
-
|
|
385
|
-
const afs = new AFS({
|
|
386
|
-
animation: {
|
|
387
|
-
type: 'fade', // fade, slide, scale, flip, rotate, zoom, bounce, blur, etc.
|
|
388
|
-
duration: 400,
|
|
389
|
-
easing: 'ease-out'
|
|
390
|
-
}
|
|
391
|
-
});
|
|
116
|
+
## Documentation
|
|
392
117
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
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 |
|
|
396
128
|
|
|
397
|
-
##
|
|
129
|
+
## Common options
|
|
130
|
+
|
|
131
|
+
All options with their defaults live in [`src/core/Options.js`](src/core/Options.js). The ones you'll touch most:
|
|
398
132
|
|
|
399
133
|
```javascript
|
|
400
134
|
const afs = new AFS({
|
|
401
|
-
|
|
402
|
-
|
|
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
|
-
urlStateKey: 'filters',
|
|
449
|
-
|
|
450
|
-
// Styling
|
|
451
|
-
styles: {
|
|
452
|
-
colors: {
|
|
453
|
-
primary: '#000',
|
|
454
|
-
background: '#f5f5f5',
|
|
455
|
-
text: '#333'
|
|
456
|
-
},
|
|
457
|
-
button: {
|
|
458
|
-
borderRadius: '6px',
|
|
459
|
-
padding: '8px 16px'
|
|
460
|
-
}
|
|
461
|
-
},
|
|
462
|
-
|
|
463
|
-
// Debug mode
|
|
464
|
-
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
|
|
465
182
|
});
|
|
466
183
|
```
|
|
467
184
|
|
|
468
|
-
## API
|
|
185
|
+
## API at a glance
|
|
469
186
|
|
|
470
|
-
|
|
187
|
+
Each feature lives on the instance: `afs.filter`, `afs.search`, `afs.sort`, `afs.pagination`, `afs.rangeFilter`, `afs.inputRangeFilter`, `afs.dateFilter`, `afs.urlManager`.
|
|
471
188
|
|
|
472
189
|
```javascript
|
|
473
|
-
//
|
|
190
|
+
// Filtering
|
|
474
191
|
afs.filter.addFilter('category:tech');
|
|
475
192
|
afs.filter.removeFilter('category:tech');
|
|
476
|
-
afs.filter.clearAllFilters();
|
|
477
|
-
afs.filter.setFilterTypeLogic('brand', 'AND');
|
|
193
|
+
afs.filter.clearAllFilters(); // filters + search + dropdowns + checkboxes
|
|
478
194
|
|
|
479
195
|
// Search
|
|
480
|
-
afs.search.
|
|
196
|
+
afs.search.setValue('macbook');
|
|
481
197
|
afs.search.clearSearch();
|
|
482
198
|
|
|
483
199
|
// Sorting
|
|
484
|
-
afs.
|
|
485
|
-
afs.
|
|
200
|
+
afs.sort.sort('price', 'desc');
|
|
201
|
+
afs.sort.shuffle();
|
|
202
|
+
afs.sort.reset();
|
|
486
203
|
|
|
487
204
|
// Pagination
|
|
488
205
|
afs.pagination.goToPage(2);
|
|
489
206
|
afs.pagination.nextPage();
|
|
490
|
-
afs.pagination.
|
|
491
|
-
|
|
492
|
-
// State
|
|
493
|
-
const state = afs.getState();
|
|
494
|
-
afs.setState(state);
|
|
207
|
+
afs.pagination.setItemsPerPage(24);
|
|
208
|
+
afs.pagination.getPageInfo(); // { currentPage, itemsPerPage, totalPages }
|
|
495
209
|
|
|
496
|
-
//
|
|
497
|
-
afs.
|
|
498
|
-
|
|
210
|
+
// Range widgets (containers are DOM elements)
|
|
211
|
+
afs.rangeFilter.addRangeSlider({
|
|
212
|
+
key: 'price', type: 'number',
|
|
213
|
+
container: document.querySelector('.price-slider'),
|
|
214
|
+
min: 0, max: 1000, step: 10,
|
|
215
|
+
ui: { showHistogram: true, bins: 12 },
|
|
499
216
|
});
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
### Event System
|
|
217
|
+
afs.inputRangeFilter.addInputRange({ key: 'rating', container: el, min: 0, max: 5, step: 0.5 });
|
|
218
|
+
afs.dateFilter.addDateRange({ key: 'date', container: el });
|
|
503
219
|
|
|
504
|
-
|
|
505
|
-
//
|
|
506
|
-
afs.
|
|
507
|
-
afs.on('search:performed', callback);
|
|
508
|
-
afs.on('sort:applied', callback);
|
|
509
|
-
afs.on('pagination:changed', callback);
|
|
510
|
-
afs.on('state:changed', callback);
|
|
220
|
+
// Lifecycle
|
|
221
|
+
afs.refresh(); // re-scan items (after DOM changes)
|
|
222
|
+
afs.destroy();
|
|
511
223
|
```
|
|
512
224
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
The project includes comprehensive examples demonstrating all features:
|
|
516
|
-
|
|
517
|
-
- **[Interactive Demo](examples/demo.html)** - Complete demo with all filter types
|
|
518
|
-
- **[Button Filters](examples/demo.html#buttons)** - Toggle and multi-select buttons
|
|
519
|
-
- **[Select Dropdowns](examples/demo.html#select)** - Dropdown filter controls
|
|
520
|
-
- **[Radio Buttons](examples/demo.html#radio)** - Exclusive radio button filters
|
|
521
|
-
- **[Checkboxes](examples/demo.html#checkbox)** - Multi-select checkbox filters
|
|
522
|
-
- **[Range Filters](examples/demo.html#range)** - Sliders with histogram support
|
|
523
|
-
- **[Search Functionality](examples/demo.html#search)** - Real-time search examples
|
|
524
|
-
|
|
525
|
-
### Running Examples Locally
|
|
225
|
+
### Events
|
|
526
226
|
|
|
527
|
-
```
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
227
|
+
```javascript
|
|
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 }) => { /* … */ });
|
|
534
234
|
```
|
|
535
235
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
- Chrome (latest)
|
|
539
|
-
- Firefox (latest)
|
|
540
|
-
- Safari (latest)
|
|
541
|
-
- Edge (latest)
|
|
542
|
-
- Opera (latest)
|
|
236
|
+
`on`, `once`, `off`, `removeAllListeners` are available. Each module's documentation lists its events and payloads.
|
|
543
237
|
|
|
544
|
-
|
|
545
|
-
- ES6 Modules
|
|
546
|
-
- CSS Custom Properties
|
|
547
|
-
- IntersectionObserver API
|
|
548
|
-
- URLSearchParams API
|
|
238
|
+
## TypeScript
|
|
549
239
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
Full TypeScript support with comprehensive type definitions:
|
|
240
|
+
Type definitions ship with the package:
|
|
553
241
|
|
|
554
242
|
```typescript
|
|
555
243
|
import { AFS, AFSOptions, FilterTypeLogic } from 'advanced-filter-system';
|
|
556
244
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
const filterLogic: FilterTypeLogic = {
|
|
562
|
-
category: { mode: 'OR', multi: true },
|
|
563
|
-
brand: 'OR'
|
|
245
|
+
const logic: FilterTypeLogic = {
|
|
246
|
+
category: { mode: 'OR', multi: true },
|
|
247
|
+
brand: 'OR',
|
|
564
248
|
};
|
|
565
249
|
|
|
566
250
|
const afs = new AFS({
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
}
|
|
251
|
+
containerSelector: '#items',
|
|
252
|
+
itemSelector: '.item',
|
|
253
|
+
filterTypeLogic: logic,
|
|
254
|
+
});
|
|
571
255
|
```
|
|
572
256
|
|
|
573
|
-
##
|
|
257
|
+
## Browser support
|
|
574
258
|
|
|
575
|
-
|
|
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.
|
|
576
260
|
|
|
577
|
-
|
|
578
|
-
2. Code style and standards
|
|
579
|
-
3. Testing requirements
|
|
580
|
-
4. Pull request process
|
|
581
|
-
5. Bug reporting guidelines
|
|
582
|
-
6. Feature request templates
|
|
583
|
-
|
|
584
|
-
### Development Setup
|
|
261
|
+
## Development
|
|
585
262
|
|
|
586
263
|
```bash
|
|
587
|
-
# Clone and install
|
|
588
264
|
git clone https://github.com/misits/advanced-filter-system.git
|
|
589
265
|
cd advanced-filter-system
|
|
590
266
|
npm install
|
|
591
267
|
|
|
592
|
-
#
|
|
593
|
-
npm run
|
|
594
|
-
|
|
595
|
-
# Build for production
|
|
596
|
-
npm run build
|
|
268
|
+
npm test # jest test suite
|
|
269
|
+
npm run build # build dist/ (development)
|
|
270
|
+
npm run build:prod # minified production build
|
|
597
271
|
|
|
598
|
-
#
|
|
599
|
-
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
|
|
600
275
|
```
|
|
601
276
|
|
|
602
277
|
## License
|
|
603
278
|
|
|
604
|
-
|
|
279
|
+
MIT — see [LICENSE](LICENSE).
|
|
605
280
|
|
|
606
281
|
---
|
|
607
282
|
|
|
608
283
|
Made with ♥ by [misits](https://github.com/misits)
|
|
609
|
-
|
|
610
|
-
**Star ⭐ this repo if you find it helpful!**
|