advanced-filter-system 1.0.0 → 1.0.2

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.
@@ -1,483 +0,0 @@
1
- /**
2
- * @fileoverview Advanced Filter System for DOM elements
3
- * @version 1.0.0
4
- *
5
- * A flexible and customizable filtering system that supports:
6
- * - Multiple filtering modes (OR/AND)
7
- * - Text search with debouncing
8
- * - Multiple sorting criteria
9
- * - Range filtering
10
- * - URL state management
11
- * - Animation and transitions
12
- * - Results counter
13
- */
14
-
15
- /**
16
- * Utility function for debouncing
17
- * @param {Function} func - Function to debounce
18
- * @param {number} wait - Delay in milliseconds
19
- * @returns {Function} Debounced function
20
- */
21
- function debounce(func, wait) {
22
- let timeout;
23
- return function executedFunction(...args) {
24
- const later = () => {
25
- clearTimeout(timeout);
26
- func(...args);
27
- };
28
- clearTimeout(timeout);
29
- timeout = setTimeout(later, wait);
30
- };
31
- }
32
- class Filter {
33
- /**
34
- * @typedef {Object} FilterOptions
35
- * @property {string} containerSelector - Main container selector
36
- * @property {string} itemSelector - Items to filter selector
37
- * @property {string} filterButtonSelector - Filter buttons selector
38
- * @property {string} [searchInputSelector] - Search input selector
39
- * @property {string} [counterSelector] - Results counter selector
40
- * @property {string} [activeClass='active'] - Active state class
41
- * @property {string} [hiddenClass='hidden'] - Hidden state class
42
- * @property {number} [animationDuration=300] - Animation duration in ms
43
- * @property {string} [filterMode='OR'] - Filter mode ('OR' or 'AND')
44
- * @property {string[]} [searchKeys=['title']] - Data attributes to search in
45
- * @property {number} [debounceTime=300] - Search debounce delay in ms
46
- */
47
-
48
- /**
49
- * @param {FilterOptions} options - Filter configuration options
50
- */
51
- constructor(options = {}) {
52
- this.options = {
53
- containerSelector: '.filter-container',
54
- itemSelector: '.filter-item',
55
- filterButtonSelector: '.btn-filter',
56
- searchInputSelector: '.filter-search',
57
- counterSelector: '.filter-counter',
58
- activeClass: 'active',
59
- hiddenClass: 'hidden',
60
- animationDuration: 300,
61
- filterMode: 'OR',
62
- searchKeys: ['title'],
63
- debounceTime: 300,
64
- ...options
65
- };
66
-
67
- // Initialize elements
68
- this.container = document.querySelector(this.options.containerSelector);
69
- this.items = document.querySelectorAll(this.options.itemSelector);
70
- this.filterButtons = document.querySelectorAll(this.options.filterButtonSelector);
71
- this.searchInput = document.querySelector(this.options.searchInputSelector);
72
- this.counter = document.querySelector(this.options.counterSelector);
73
-
74
- // Initialize state
75
- this.currentFilters = new Set(['*']);
76
- this.currentSearch = '';
77
- this.visibleItems = new Set(this.items);
78
- this.init();
79
- }
80
-
81
- /**
82
- * Initialize the filter system
83
- * @private
84
- */
85
- init() {
86
- this.addStyles();
87
- this.bindEvents();
88
- this.loadFromURL();
89
- this.updateCounter();
90
- }
91
-
92
- /**
93
- * Add required styles to document
94
- * @private
95
- */
96
- addStyles() {
97
- const styles = `
98
- .${this.options.hiddenClass} {
99
- display: none !important;
100
- }
101
-
102
- ${this.options.itemSelector} {
103
- opacity: 1;
104
- transform: scale(1);
105
- transition: opacity ${this.options.animationDuration}ms ease-out,
106
- transform ${this.options.animationDuration}ms ease-out;
107
- }
108
-
109
- ${this.options.filterButtonSelector} {
110
- opacity: 0.5;
111
- transition: opacity ${this.options.animationDuration}ms ease;
112
- }
113
-
114
- ${this.options.filterButtonSelector}.${this.options.activeClass} {
115
- opacity: 1;
116
- }
117
- `;
118
- const styleSheet = document.createElement('style');
119
- styleSheet.textContent = styles;
120
- document.head.appendChild(styleSheet);
121
- }
122
-
123
- /**
124
- * Bind all event listeners
125
- * @private
126
- */
127
- bindEvents() {
128
- this.filterButtons.forEach(button => {
129
- button.addEventListener('click', () => this.handleFilterClick(button));
130
- });
131
- if (this.searchInput) {
132
- this.searchInput.addEventListener('input', debounce(e => {
133
- this.search(e.target.value);
134
- }, this.options.debounceTime));
135
- }
136
- window.addEventListener('popstate', () => this.loadFromURL());
137
- }
138
-
139
- /**
140
- * Handle filter button clicks
141
- * @private
142
- * @param {HTMLElement} button - Clicked filter button
143
- */
144
- handleFilterClick(button) {
145
- const filterValue = button.dataset.filter;
146
- if (filterValue === '*') {
147
- this.resetFilters();
148
- } else {
149
- this.toggleFilter(filterValue, button);
150
- }
151
- this.filter();
152
- this.updateURL();
153
- }
154
-
155
- /**
156
- * Reset all filters to default state
157
- * @private
158
- */
159
- resetFilters() {
160
- this.filterButtons.forEach(btn => btn.classList.remove(this.options.activeClass));
161
- this.currentFilters.clear();
162
- this.currentFilters.add('*');
163
- this.filterButtons[0].classList.add(this.options.activeClass);
164
- this.resetCounter();
165
- }
166
-
167
- /**
168
- * Reset visible items counter
169
- * @private
170
- */
171
- resetCounter() {
172
- this.visibleItems = new Set(this.items);
173
- this.updateCounter();
174
- }
175
-
176
- /**
177
- * Toggle individual filter state
178
- * @private
179
- * @param {string} filterValue - Filter value to toggle
180
- * @param {HTMLElement} button - Filter button element
181
- */
182
- toggleFilter(filterValue, button) {
183
- this.currentFilters.delete('*');
184
- this.filterButtons[0].classList.remove(this.options.activeClass);
185
- if (button.classList.contains(this.options.activeClass)) {
186
- button.classList.remove(this.options.activeClass);
187
- this.currentFilters.delete(filterValue);
188
- if (this.currentFilters.size === 0) {
189
- this.resetFilters();
190
- }
191
- } else {
192
- button.classList.add(this.options.activeClass);
193
- this.currentFilters.add(filterValue);
194
- }
195
- }
196
-
197
- /**
198
- * Apply current filters to items
199
- * @public
200
- */
201
- filter() {
202
- this.items.forEach(item => {
203
- if (this.currentFilters.has('*')) {
204
- this.showItem(item);
205
- return;
206
- }
207
- const itemCategories = new Set(item.dataset.categories?.split(' ') || []);
208
- const matchesFilter = this.options.filterMode === 'OR' ? this.matchesAnyFilter(itemCategories) : this.matchesAllFilters(itemCategories);
209
- if (matchesFilter) {
210
- this.showItem(item);
211
- } else {
212
- this.hideItem(item);
213
- }
214
- });
215
- setTimeout(() => {
216
- this.updateCounter();
217
- }, this.options.animationDuration);
218
- }
219
-
220
- /**
221
- * Check if item matches any active filter (OR mode)
222
- * @private
223
- * @param {Set} itemCategories - Item's categories
224
- * @returns {boolean} Whether item matches any filter
225
- */
226
- matchesAnyFilter(itemCategories) {
227
- return [...this.currentFilters].some(filter => {
228
- const [type, value] = filter.split(':');
229
- return itemCategories.has(`${type}:${value}`);
230
- });
231
- }
232
-
233
- /**
234
- * Check if item matches all active filters (AND mode)
235
- * @private
236
- * @param {Set} itemCategories - Item's categories
237
- * @returns {boolean} Whether item matches all filters
238
- */
239
- matchesAllFilters(itemCategories) {
240
- return [...this.currentFilters].every(filter => {
241
- const [type, value] = filter.split(':');
242
- return itemCategories.has(`${type}:${value}`);
243
- });
244
- }
245
-
246
- /**
247
- * Show an item with animation
248
- * @private
249
- * @param {HTMLElement} item - Item to show
250
- */
251
- showItem(item) {
252
- this.visibleItems.add(item);
253
- item.classList.remove(this.options.hiddenClass);
254
- item.style.opacity = '0';
255
- item.style.transform = 'scale(0.95)';
256
- item.offsetHeight;
257
- requestAnimationFrame(() => {
258
- item.style.opacity = '1';
259
- item.style.transform = 'scale(1)';
260
- });
261
- }
262
-
263
- /**
264
- * Hide an item with animation
265
- * @private
266
- * @param {HTMLElement} item - Item to hide
267
- */
268
- hideItem(item) {
269
- item.style.opacity = '0';
270
- item.style.transform = 'scale(0.95)';
271
- setTimeout(() => {
272
- if (item.style.opacity === '0') {
273
- item.classList.add(this.options.hiddenClass);
274
- this.visibleItems.delete(item);
275
- }
276
- }, this.options.animationDuration);
277
- }
278
-
279
- /**
280
- * Search items by text
281
- * @public
282
- * @param {string} query - Search query
283
- */
284
- search(query) {
285
- this.currentSearch = query.toLowerCase().trim();
286
- this.items.forEach(item => {
287
- const searchText = this.options.searchKeys.map(key => item.dataset[key] || '').join(' ').toLowerCase();
288
- const matchesSearch = this.currentSearch === '' || searchText.includes(this.currentSearch);
289
- if (matchesSearch) {
290
- this.showItem(item);
291
- } else {
292
- this.hideItem(item);
293
- }
294
- });
295
- this.updateURL();
296
- setTimeout(() => {
297
- this.updateCounter();
298
- }, this.options.animationDuration);
299
- }
300
-
301
- /**
302
- * Sort items by multiple criteria
303
- * @public
304
- * @param {Array<{key: string, direction: string}>} criteria - Sort criteria
305
- */
306
- sortMultiple(criteria) {
307
- const items = [...this.items];
308
- items.sort((a, b) => {
309
- for (const criterion of criteria) {
310
- const valueA = a.dataset[criterion.key];
311
- const valueB = b.dataset[criterion.key];
312
- const comparison = criterion.direction === 'asc' ? valueA.localeCompare(valueB) : valueB.localeCompare(valueA);
313
- if (comparison !== 0) return comparison;
314
- }
315
- return 0;
316
- });
317
- items.forEach(item => this.container.appendChild(item));
318
- }
319
-
320
- /**
321
- * Filter items by numeric range
322
- * @public
323
- * @param {string} key - Data attribute key
324
- * @param {number} min - Minimum value
325
- * @param {number} max - Maximum value
326
- */
327
- addRangeFilter(key, min, max) {
328
- this.items.forEach(item => {
329
- const value = parseFloat(item.dataset[key]);
330
- const inRange = value >= min && value <= max;
331
- if (inRange) {
332
- this.showItem(item);
333
- } else {
334
- this.hideItem(item);
335
- }
336
- });
337
- setTimeout(() => {
338
- this.updateCounter();
339
- }, this.options.animationDuration);
340
- }
341
-
342
- /**
343
- * Update URL with current filter state
344
- * @private
345
- */
346
- updateURL() {
347
- const params = new URLSearchParams();
348
-
349
- // Séparer les filtres par type
350
- const filtersByType = {};
351
- for (const filter of this.currentFilters) {
352
- if (filter !== '*') {
353
- const [type, value] = filter.split(':');
354
- if (!filtersByType[type]) {
355
- filtersByType[type] = new Set();
356
- }
357
- filtersByType[type].add(value);
358
- }
359
- }
360
-
361
- // Ajouter chaque type de filtre à l'URL
362
- Object.entries(filtersByType).forEach(([type, values]) => {
363
- params.set(type, Array.from(values).join(','));
364
- });
365
- if (this.currentSearch) {
366
- params.set('search', this.currentSearch);
367
- }
368
- const newURL = `${window.location.pathname}${params.toString() ? '?' + params.toString() : ''}`;
369
- window.history.pushState({}, '', newURL);
370
- }
371
-
372
- /**
373
- * Load filter state from URL
374
- * @private
375
- */
376
- loadFromURL() {
377
- const params = new URLSearchParams(window.location.search);
378
- this.currentFilters.clear();
379
-
380
- // Si aucun filtre n'est présent, utiliser '*'
381
- let hasFilters = false;
382
-
383
- // Parcourir tous les paramètres
384
- for (const [type, values] of params.entries()) {
385
- if (type !== 'search') {
386
- hasFilters = true;
387
- values.split(',').forEach(value => {
388
- this.currentFilters.add(`${type}:${value}`);
389
- });
390
- }
391
- }
392
- if (!hasFilters) {
393
- this.currentFilters.add('*');
394
- }
395
-
396
- // Update active buttons
397
- this.filterButtons.forEach(button => {
398
- const filterValue = button.dataset.filter;
399
- if (this.currentFilters.has(filterValue) || filterValue === '*' && this.currentFilters.has('*')) {
400
- button.classList.add(this.options.activeClass);
401
- } else {
402
- button.classList.remove(this.options.activeClass);
403
- }
404
- });
405
-
406
- // Load search
407
- const search = params.get('search') || '';
408
- if (this.searchInput) {
409
- this.searchInput.value = search;
410
- }
411
- this.filter();
412
- if (search) {
413
- this.search(search);
414
- }
415
- }
416
-
417
- /**
418
- * Update results counter
419
- * @private
420
- * @returns {{total: number, visible: number}}
421
- */
422
- updateCounter() {
423
- const total = this.items.length;
424
- const visible = this.visibleItems.size;
425
- if (this.counter) {
426
- this.counter.textContent = `Showing ${visible} of ${total}`;
427
- }
428
- return {
429
- total,
430
- visible
431
- };
432
- }
433
-
434
- /**
435
- * Change filter mode
436
- * @public
437
- * @param {string} mode - New filter mode ('OR' or 'AND')
438
- */
439
- setFilterMode(mode) {
440
- if (['OR', 'AND'].includes(mode.toUpperCase())) {
441
- this.options.filterMode = mode.toUpperCase();
442
- this.filter();
443
- }
444
- }
445
-
446
- /**
447
- * Add filter by type and value
448
- * @public
449
- * @param {string} type - Filter type
450
- * @param {string} value - Filter value
451
- */
452
- addFilter(type, value) {
453
- this.currentFilters.add(`${type}:${value}`);
454
- this.filter();
455
- this.updateURL();
456
- }
457
-
458
- /**
459
- * Remove filter by type and value
460
- * @public
461
- * @param {string} type - Filter type
462
- */
463
- removeFilter(type, value) {
464
- this.currentFilters.delete(`${type}:${value}`);
465
- if (this.currentFilters.size === 0) {
466
- this.currentFilters.add('*');
467
- }
468
- this.filter();
469
- this.updateURL();
470
- }
471
-
472
- /**
473
- * Get active filters by type
474
- * @public
475
- * @param {string} type - Filter type
476
- */
477
- getActiveFiltersByType(type) {
478
- return [...this.currentFilters].filter(filter => filter.startsWith(`${type}:`)).map(filter => filter.split(':')[1]);
479
- }
480
- }
481
-
482
- export { Filter };
483
- //# sourceMappingURL=filter.esm.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"filter.esm.js","sources":["../src/index.js"],"sourcesContent":["/**\n * @fileoverview Advanced Filter System for DOM elements\n * @version 1.0.0\n * \n * A flexible and customizable filtering system that supports:\n * - Multiple filtering modes (OR/AND)\n * - Text search with debouncing\n * - Multiple sorting criteria\n * - Range filtering\n * - URL state management\n * - Animation and transitions\n * - Results counter\n */\n\n/**\n * Utility function for debouncing\n * @param {Function} func - Function to debounce\n * @param {number} wait - Delay in milliseconds\n * @returns {Function} Debounced function\n */\nfunction debounce(func, wait) {\n let timeout;\n return function executedFunction(...args) {\n const later = () => {\n clearTimeout(timeout);\n func(...args);\n };\n clearTimeout(timeout);\n timeout = setTimeout(later, wait);\n };\n}\n\nclass Filter {\n /**\n * @typedef {Object} FilterOptions\n * @property {string} containerSelector - Main container selector\n * @property {string} itemSelector - Items to filter selector\n * @property {string} filterButtonSelector - Filter buttons selector\n * @property {string} [searchInputSelector] - Search input selector\n * @property {string} [counterSelector] - Results counter selector\n * @property {string} [activeClass='active'] - Active state class\n * @property {string} [hiddenClass='hidden'] - Hidden state class\n * @property {number} [animationDuration=300] - Animation duration in ms\n * @property {string} [filterMode='OR'] - Filter mode ('OR' or 'AND')\n * @property {string[]} [searchKeys=['title']] - Data attributes to search in\n * @property {number} [debounceTime=300] - Search debounce delay in ms\n */\n\n /**\n * @param {FilterOptions} options - Filter configuration options\n */\n constructor(options = {}) {\n this.options = {\n containerSelector: '.filter-container',\n itemSelector: '.filter-item',\n filterButtonSelector: '.btn-filter',\n searchInputSelector: '.filter-search',\n counterSelector: '.filter-counter',\n activeClass: 'active',\n hiddenClass: 'hidden',\n animationDuration: 300,\n filterMode: 'OR',\n searchKeys: ['title'],\n debounceTime: 300,\n ...options,\n };\n\n // Initialize elements\n this.container = document.querySelector(this.options.containerSelector);\n this.items = document.querySelectorAll(this.options.itemSelector);\n this.filterButtons = document.querySelectorAll(this.options.filterButtonSelector);\n this.searchInput = document.querySelector(this.options.searchInputSelector);\n this.counter = document.querySelector(this.options.counterSelector);\n\n // Initialize state\n this.currentFilters = new Set(['*']);\n this.currentSearch = '';\n this.visibleItems = new Set(this.items);\n\n this.init();\n }\n\n /**\n * Initialize the filter system\n * @private\n */\n init() {\n this.addStyles();\n this.bindEvents();\n this.loadFromURL();\n this.updateCounter();\n }\n\n /**\n * Add required styles to document\n * @private\n */\n addStyles() {\n const styles = `\n .${this.options.hiddenClass} {\n display: none !important;\n }\n\n ${this.options.itemSelector} {\n opacity: 1;\n transform: scale(1);\n transition: opacity ${this.options.animationDuration}ms ease-out,\n transform ${this.options.animationDuration}ms ease-out;\n }\n\n ${this.options.filterButtonSelector} {\n opacity: 0.5;\n transition: opacity ${this.options.animationDuration}ms ease;\n }\n\n ${this.options.filterButtonSelector}.${this.options.activeClass} {\n opacity: 1;\n }\n `;\n\n const styleSheet = document.createElement('style');\n styleSheet.textContent = styles;\n document.head.appendChild(styleSheet);\n }\n\n /**\n * Bind all event listeners\n * @private\n */\n bindEvents() {\n this.filterButtons.forEach(button => {\n button.addEventListener('click', () => this.handleFilterClick(button));\n });\n\n if (this.searchInput) {\n this.searchInput.addEventListener('input', debounce((e) => {\n this.search(e.target.value);\n }, this.options.debounceTime));\n }\n\n window.addEventListener('popstate', () => this.loadFromURL());\n }\n\n /**\n * Handle filter button clicks\n * @private\n * @param {HTMLElement} button - Clicked filter button\n */\n handleFilterClick(button) {\n const filterValue = button.dataset.filter;\n\n if (filterValue === '*') {\n this.resetFilters();\n } else {\n this.toggleFilter(filterValue, button);\n }\n\n this.filter();\n this.updateURL();\n }\n\n /**\n * Reset all filters to default state\n * @private\n */\n resetFilters() {\n this.filterButtons.forEach(btn => btn.classList.remove(this.options.activeClass));\n this.currentFilters.clear();\n this.currentFilters.add('*');\n this.filterButtons[0].classList.add(this.options.activeClass);\n this.resetCounter();\n }\n\n /**\n * Reset visible items counter\n * @private\n */\n resetCounter() {\n this.visibleItems = new Set(this.items);\n this.updateCounter();\n }\n\n /**\n * Toggle individual filter state\n * @private\n * @param {string} filterValue - Filter value to toggle\n * @param {HTMLElement} button - Filter button element\n */\n toggleFilter(filterValue, button) {\n this.currentFilters.delete('*');\n this.filterButtons[0].classList.remove(this.options.activeClass);\n\n if (button.classList.contains(this.options.activeClass)) {\n button.classList.remove(this.options.activeClass);\n this.currentFilters.delete(filterValue);\n\n if (this.currentFilters.size === 0) {\n this.resetFilters();\n }\n } else {\n button.classList.add(this.options.activeClass);\n this.currentFilters.add(filterValue);\n }\n }\n\n /**\n * Apply current filters to items\n * @public\n */\n filter() {\n this.items.forEach(item => {\n if (this.currentFilters.has('*')) {\n this.showItem(item);\n return;\n }\n\n const itemCategories = new Set(item.dataset.categories?.split(' ') || []);\n const matchesFilter = this.options.filterMode === 'OR'\n ? this.matchesAnyFilter(itemCategories)\n : this.matchesAllFilters(itemCategories);\n\n if (matchesFilter) {\n this.showItem(item);\n } else {\n this.hideItem(item);\n }\n });\n\n setTimeout(() => {\n this.updateCounter();\n }, this.options.animationDuration);\n }\n\n /**\n * Check if item matches any active filter (OR mode)\n * @private\n * @param {Set} itemCategories - Item's categories\n * @returns {boolean} Whether item matches any filter\n */\n matchesAnyFilter(itemCategories) {\n return [...this.currentFilters].some(filter => {\n const [type, value] = filter.split(':');\n return itemCategories.has(`${type}:${value}`);\n });\n }\n\n /**\n * Check if item matches all active filters (AND mode)\n * @private\n * @param {Set} itemCategories - Item's categories\n * @returns {boolean} Whether item matches all filters\n */\n matchesAllFilters(itemCategories) {\n return [...this.currentFilters].every(filter => {\n const [type, value] = filter.split(':');\n return itemCategories.has(`${type}:${value}`);\n });\n }\n\n /**\n * Show an item with animation\n * @private\n * @param {HTMLElement} item - Item to show\n */\n showItem(item) {\n this.visibleItems.add(item);\n item.classList.remove(this.options.hiddenClass);\n item.style.opacity = '0';\n item.style.transform = 'scale(0.95)';\n \n item.offsetHeight;\n \n requestAnimationFrame(() => {\n item.style.opacity = '1';\n item.style.transform = 'scale(1)';\n });\n }\n\n /**\n * Hide an item with animation\n * @private\n * @param {HTMLElement} item - Item to hide\n */\n hideItem(item) {\n item.style.opacity = '0';\n item.style.transform = 'scale(0.95)';\n \n setTimeout(() => {\n if (item.style.opacity === '0') {\n item.classList.add(this.options.hiddenClass);\n this.visibleItems.delete(item);\n }\n }, this.options.animationDuration);\n }\n\n /**\n * Search items by text\n * @public\n * @param {string} query - Search query\n */\n search(query) {\n this.currentSearch = query.toLowerCase().trim();\n let matches = 0;\n \n this.items.forEach(item => {\n const searchText = this.options.searchKeys\n .map(key => item.dataset[key] || '')\n .join(' ')\n .toLowerCase();\n\n const matchesSearch = this.currentSearch === '' || \n searchText.includes(this.currentSearch);\n\n if (matchesSearch) {\n this.showItem(item);\n matches++;\n } else {\n this.hideItem(item);\n }\n });\n\n this.updateURL();\n \n setTimeout(() => {\n this.updateCounter();\n }, this.options.animationDuration);\n }\n\n /**\n * Sort items by multiple criteria\n * @public\n * @param {Array<{key: string, direction: string}>} criteria - Sort criteria\n */\n sortMultiple(criteria) {\n const items = [...this.items];\n \n items.sort((a, b) => {\n for (const criterion of criteria) {\n const valueA = a.dataset[criterion.key];\n const valueB = b.dataset[criterion.key];\n \n const comparison = criterion.direction === 'asc'\n ? valueA.localeCompare(valueB)\n : valueB.localeCompare(valueA);\n \n if (comparison !== 0) return comparison;\n }\n return 0;\n });\n\n items.forEach(item => this.container.appendChild(item));\n }\n\n /**\n * Filter items by numeric range\n * @public\n * @param {string} key - Data attribute key\n * @param {number} min - Minimum value\n * @param {number} max - Maximum value\n */\n addRangeFilter(key, min, max) {\n this.items.forEach(item => {\n const value = parseFloat(item.dataset[key]);\n const inRange = value >= min && value <= max;\n \n if (inRange) {\n this.showItem(item);\n } else {\n this.hideItem(item);\n }\n });\n\n setTimeout(() => {\n this.updateCounter();\n }, this.options.animationDuration);\n }\n\n /**\n * Update URL with current filter state\n * @private\n */\n updateURL() {\n const params = new URLSearchParams();\n \n // Séparer les filtres par type\n const filtersByType = {};\n for (const filter of this.currentFilters) {\n if (filter !== '*') {\n const [type, value] = filter.split(':');\n if (!filtersByType[type]) {\n filtersByType[type] = new Set();\n }\n filtersByType[type].add(value);\n }\n }\n \n // Ajouter chaque type de filtre à l'URL\n Object.entries(filtersByType).forEach(([type, values]) => {\n params.set(type, Array.from(values).join(','));\n });\n \n if (this.currentSearch) {\n params.set('search', this.currentSearch);\n }\n \n const newURL = `${window.location.pathname}${params.toString() ? '?' + params.toString() : ''}`;\n window.history.pushState({}, '', newURL);\n }\n\n /**\n * Load filter state from URL\n * @private\n */\n loadFromURL() {\n const params = new URLSearchParams(window.location.search);\n this.currentFilters.clear();\n \n // Si aucun filtre n'est présent, utiliser '*'\n let hasFilters = false;\n \n // Parcourir tous les paramètres\n for (const [type, values] of params.entries()) {\n if (type !== 'search') {\n hasFilters = true;\n values.split(',').forEach(value => {\n this.currentFilters.add(`${type}:${value}`);\n });\n }\n }\n \n if (!hasFilters) {\n this.currentFilters.add('*');\n }\n \n // Update active buttons\n this.filterButtons.forEach(button => {\n const filterValue = button.dataset.filter;\n if (this.currentFilters.has(filterValue) || \n (filterValue === '*' && this.currentFilters.has('*'))) {\n button.classList.add(this.options.activeClass);\n } else {\n button.classList.remove(this.options.activeClass);\n }\n });\n \n // Load search\n const search = params.get('search') || '';\n if (this.searchInput) {\n this.searchInput.value = search;\n }\n \n this.filter();\n if (search) {\n this.search(search);\n }\n }\n\n /**\n * Update results counter\n * @private\n * @returns {{total: number, visible: number}}\n */\n updateCounter() {\n const total = this.items.length;\n const visible = this.visibleItems.size;\n \n if (this.counter) {\n this.counter.textContent = `Showing ${visible} of ${total}`;\n }\n \n return { total, visible };\n }\n\n /**\n * Change filter mode\n * @public\n * @param {string} mode - New filter mode ('OR' or 'AND')\n */\n setFilterMode(mode) {\n if (['OR', 'AND'].includes(mode.toUpperCase())) {\n this.options.filterMode = mode.toUpperCase();\n this.filter();\n }\n }\n\n /**\n * Add filter by type and value\n * @public\n * @param {string} type - Filter type\n * @param {string} value - Filter value\n */\n addFilter(type, value) {\n this.currentFilters.add(`${type}:${value}`);\n this.filter();\n this.updateURL();\n }\n \n /**\n * Remove filter by type and value\n * @public\n * @param {string} type - Filter type\n */\n removeFilter(type, value) {\n this.currentFilters.delete(`${type}:${value}`);\n if (this.currentFilters.size === 0) {\n this.currentFilters.add('*');\n }\n this.filter();\n this.updateURL();\n }\n \n /**\n * Get active filters by type\n * @public\n * @param {string} type - Filter type\n */\n getActiveFiltersByType(type) {\n return [...this.currentFilters]\n .filter(filter => filter.startsWith(`${type}:`))\n .map(filter => filter.split(':')[1]);\n }\n}\n\nexport { Filter };"],"names":["debounce","func","wait","timeout","executedFunction","args","later","clearTimeout","setTimeout","Filter","constructor","options","containerSelector","itemSelector","filterButtonSelector","searchInputSelector","counterSelector","activeClass","hiddenClass","animationDuration","filterMode","searchKeys","debounceTime","container","document","querySelector","items","querySelectorAll","filterButtons","searchInput","counter","currentFilters","Set","currentSearch","visibleItems","init","addStyles","bindEvents","loadFromURL","updateCounter","styles","styleSheet","createElement","textContent","head","appendChild","forEach","button","addEventListener","handleFilterClick","e","search","target","value","window","filterValue","dataset","filter","resetFilters","toggleFilter","updateURL","btn","classList","remove","clear","add","resetCounter","delete","contains","size","item","has","showItem","itemCategories","categories","split","matchesFilter","matchesAnyFilter","matchesAllFilters","hideItem","some","type","every","style","opacity","transform","offsetHeight","requestAnimationFrame","query","toLowerCase","trim","searchText","map","key","join","matchesSearch","includes","sortMultiple","criteria","sort","a","b","criterion","valueA","valueB","comparison","direction","localeCompare","addRangeFilter","min","max","parseFloat","inRange","params","URLSearchParams","filtersByType","Object","entries","values","set","Array","from","newURL","location","pathname","toString","history","pushState","hasFilters","get","total","length","visible","setFilterMode","mode","toUpperCase","addFilter","removeFilter","getActiveFiltersByType","startsWith"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAASA,QAAQA,CAACC,IAAI,EAAEC,IAAI,EAAE;AAC1B,EAAA,IAAIC,OAAO,CAAA;AACX,EAAA,OAAO,SAASC,gBAAgBA,CAAC,GAAGC,IAAI,EAAE;IACtC,MAAMC,KAAK,GAAGA,MAAM;MAChBC,YAAY,CAACJ,OAAO,CAAC,CAAA;MACrBF,IAAI,CAAC,GAAGI,IAAI,CAAC,CAAA;KAChB,CAAA;IACDE,YAAY,CAACJ,OAAO,CAAC,CAAA;AACrBA,IAAAA,OAAO,GAAGK,UAAU,CAACF,KAAK,EAAEJ,IAAI,CAAC,CAAA;GACpC,CAAA;AACL,CAAA;AAEA,MAAMO,MAAM,CAAC;AACT;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEI;AACJ;AACA;AACIC,EAAAA,WAAWA,CAACC,OAAO,GAAG,EAAE,EAAE;IACtB,IAAI,CAACA,OAAO,GAAG;AACXC,MAAAA,iBAAiB,EAAE,mBAAmB;AACtCC,MAAAA,YAAY,EAAE,cAAc;AAC5BC,MAAAA,oBAAoB,EAAE,aAAa;AACnCC,MAAAA,mBAAmB,EAAE,gBAAgB;AACrCC,MAAAA,eAAe,EAAE,iBAAiB;AAClCC,MAAAA,WAAW,EAAE,QAAQ;AACrBC,MAAAA,WAAW,EAAE,QAAQ;AACrBC,MAAAA,iBAAiB,EAAE,GAAG;AACtBC,MAAAA,UAAU,EAAE,IAAI;MAChBC,UAAU,EAAE,CAAC,OAAO,CAAC;AACrBC,MAAAA,YAAY,EAAE,GAAG;MACjB,GAAGX,OAAAA;KACN,CAAA;;AAED;AACA,IAAA,IAAI,CAACY,SAAS,GAAGC,QAAQ,CAACC,aAAa,CAAC,IAAI,CAACd,OAAO,CAACC,iBAAiB,CAAC,CAAA;AACvE,IAAA,IAAI,CAACc,KAAK,GAAGF,QAAQ,CAACG,gBAAgB,CAAC,IAAI,CAAChB,OAAO,CAACE,YAAY,CAAC,CAAA;AACjE,IAAA,IAAI,CAACe,aAAa,GAAGJ,QAAQ,CAACG,gBAAgB,CAAC,IAAI,CAAChB,OAAO,CAACG,oBAAoB,CAAC,CAAA;AACjF,IAAA,IAAI,CAACe,WAAW,GAAGL,QAAQ,CAACC,aAAa,CAAC,IAAI,CAACd,OAAO,CAACI,mBAAmB,CAAC,CAAA;AAC3E,IAAA,IAAI,CAACe,OAAO,GAAGN,QAAQ,CAACC,aAAa,CAAC,IAAI,CAACd,OAAO,CAACK,eAAe,CAAC,CAAA;;AAEnE;IACA,IAAI,CAACe,cAAc,GAAG,IAAIC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IACpC,IAAI,CAACC,aAAa,GAAG,EAAE,CAAA;IACvB,IAAI,CAACC,YAAY,GAAG,IAAIF,GAAG,CAAC,IAAI,CAACN,KAAK,CAAC,CAAA;IAEvC,IAAI,CAACS,IAAI,EAAE,CAAA;AACf,GAAA;;AAEA;AACJ;AACA;AACA;AACIA,EAAAA,IAAIA,GAAG;IACH,IAAI,CAACC,SAAS,EAAE,CAAA;IAChB,IAAI,CAACC,UAAU,EAAE,CAAA;IACjB,IAAI,CAACC,WAAW,EAAE,CAAA;IAClB,IAAI,CAACC,aAAa,EAAE,CAAA;AACxB,GAAA;;AAEA;AACJ;AACA;AACA;AACIH,EAAAA,SAASA,GAAG;AACR,IAAA,MAAMI,MAAM,GAAG,CAAA;AACvB,aAAA,EAAe,IAAI,CAAC7B,OAAO,CAACO,WAAW,CAAA;AACvC;AACA;AACA;AACA,YAAA,EAAc,IAAI,CAACP,OAAO,CAACE,YAAY,CAAA;AACvC;AACA;AACA,oCAAA,EAAsC,IAAI,CAACF,OAAO,CAACQ,iBAAiB,CAAA;AACpE,sCAAA,EAAwC,IAAI,CAACR,OAAO,CAACQ,iBAAiB,CAAA;AACtE;AACA;AACA,YAAA,EAAc,IAAI,CAACR,OAAO,CAACG,oBAAoB,CAAA;AAC/C;AACA,oCAAA,EAAsC,IAAI,CAACH,OAAO,CAACQ,iBAAiB,CAAA;AACpE;AACA;AACA,YAAc,EAAA,IAAI,CAACR,OAAO,CAACG,oBAAoB,IAAI,IAAI,CAACH,OAAO,CAACM,WAAW,CAAA;AAC3E;AACA;AACA,QAAS,CAAA,CAAA;AAED,IAAA,MAAMwB,UAAU,GAAGjB,QAAQ,CAACkB,aAAa,CAAC,OAAO,CAAC,CAAA;IAClDD,UAAU,CAACE,WAAW,GAAGH,MAAM,CAAA;AAC/BhB,IAAAA,QAAQ,CAACoB,IAAI,CAACC,WAAW,CAACJ,UAAU,CAAC,CAAA;AACzC,GAAA;;AAEA;AACJ;AACA;AACA;AACIJ,EAAAA,UAAUA,GAAG;AACT,IAAA,IAAI,CAACT,aAAa,CAACkB,OAAO,CAACC,MAAM,IAAI;AACjCA,MAAAA,MAAM,CAACC,gBAAgB,CAAC,OAAO,EAAE,MAAM,IAAI,CAACC,iBAAiB,CAACF,MAAM,CAAC,CAAC,CAAA;AAC1E,KAAC,CAAC,CAAA;IAEF,IAAI,IAAI,CAAClB,WAAW,EAAE;MAClB,IAAI,CAACA,WAAW,CAACmB,gBAAgB,CAAC,OAAO,EAAEhD,QAAQ,CAAEkD,CAAC,IAAK;QACvD,IAAI,CAACC,MAAM,CAACD,CAAC,CAACE,MAAM,CAACC,KAAK,CAAC,CAAA;AAC/B,OAAC,EAAE,IAAI,CAAC1C,OAAO,CAACW,YAAY,CAAC,CAAC,CAAA;AAClC,KAAA;IAEAgC,MAAM,CAACN,gBAAgB,CAAC,UAAU,EAAE,MAAM,IAAI,CAACV,WAAW,EAAE,CAAC,CAAA;AACjE,GAAA;;AAEA;AACJ;AACA;AACA;AACA;EACIW,iBAAiBA,CAACF,MAAM,EAAE;AACtB,IAAA,MAAMQ,WAAW,GAAGR,MAAM,CAACS,OAAO,CAACC,MAAM,CAAA;IAEzC,IAAIF,WAAW,KAAK,GAAG,EAAE;MACrB,IAAI,CAACG,YAAY,EAAE,CAAA;AACvB,KAAC,MAAM;AACH,MAAA,IAAI,CAACC,YAAY,CAACJ,WAAW,EAAER,MAAM,CAAC,CAAA;AAC1C,KAAA;IAEA,IAAI,CAACU,MAAM,EAAE,CAAA;IACb,IAAI,CAACG,SAAS,EAAE,CAAA;AACpB,GAAA;;AAEA;AACJ;AACA;AACA;AACIF,EAAAA,YAAYA,GAAG;AACX,IAAA,IAAI,CAAC9B,aAAa,CAACkB,OAAO,CAACe,GAAG,IAAIA,GAAG,CAACC,SAAS,CAACC,MAAM,CAAC,IAAI,CAACpD,OAAO,CAACM,WAAW,CAAC,CAAC,CAAA;AACjF,IAAA,IAAI,CAACc,cAAc,CAACiC,KAAK,EAAE,CAAA;AAC3B,IAAA,IAAI,CAACjC,cAAc,CAACkC,GAAG,CAAC,GAAG,CAAC,CAAA;AAC5B,IAAA,IAAI,CAACrC,aAAa,CAAC,CAAC,CAAC,CAACkC,SAAS,CAACG,GAAG,CAAC,IAAI,CAACtD,OAAO,CAACM,WAAW,CAAC,CAAA;IAC7D,IAAI,CAACiD,YAAY,EAAE,CAAA;AACvB,GAAA;;AAEA;AACJ;AACA;AACA;AACIA,EAAAA,YAAYA,GAAG;IACX,IAAI,CAAChC,YAAY,GAAG,IAAIF,GAAG,CAAC,IAAI,CAACN,KAAK,CAAC,CAAA;IACvC,IAAI,CAACa,aAAa,EAAE,CAAA;AACxB,GAAA;;AAEA;AACJ;AACA;AACA;AACA;AACA;AACIoB,EAAAA,YAAYA,CAACJ,WAAW,EAAER,MAAM,EAAE;AAC9B,IAAA,IAAI,CAAChB,cAAc,CAACoC,MAAM,CAAC,GAAG,CAAC,CAAA;AAC/B,IAAA,IAAI,CAACvC,aAAa,CAAC,CAAC,CAAC,CAACkC,SAAS,CAACC,MAAM,CAAC,IAAI,CAACpD,OAAO,CAACM,WAAW,CAAC,CAAA;AAEhE,IAAA,IAAI8B,MAAM,CAACe,SAAS,CAACM,QAAQ,CAAC,IAAI,CAACzD,OAAO,CAACM,WAAW,CAAC,EAAE;MACrD8B,MAAM,CAACe,SAAS,CAACC,MAAM,CAAC,IAAI,CAACpD,OAAO,CAACM,WAAW,CAAC,CAAA;AACjD,MAAA,IAAI,CAACc,cAAc,CAACoC,MAAM,CAACZ,WAAW,CAAC,CAAA;AAEvC,MAAA,IAAI,IAAI,CAACxB,cAAc,CAACsC,IAAI,KAAK,CAAC,EAAE;QAChC,IAAI,CAACX,YAAY,EAAE,CAAA;AACvB,OAAA;AACJ,KAAC,MAAM;MACHX,MAAM,CAACe,SAAS,CAACG,GAAG,CAAC,IAAI,CAACtD,OAAO,CAACM,WAAW,CAAC,CAAA;AAC9C,MAAA,IAAI,CAACc,cAAc,CAACkC,GAAG,CAACV,WAAW,CAAC,CAAA;AACxC,KAAA;AACJ,GAAA;;AAEA;AACJ;AACA;AACA;AACIE,EAAAA,MAAMA,GAAG;AACL,IAAA,IAAI,CAAC/B,KAAK,CAACoB,OAAO,CAACwB,IAAI,IAAI;MACvB,IAAI,IAAI,CAACvC,cAAc,CAACwC,GAAG,CAAC,GAAG,CAAC,EAAE;AAC9B,QAAA,IAAI,CAACC,QAAQ,CAACF,IAAI,CAAC,CAAA;AACnB,QAAA,OAAA;AACJ,OAAA;AAEA,MAAA,MAAMG,cAAc,GAAG,IAAIzC,GAAG,CAACsC,IAAI,CAACd,OAAO,CAACkB,UAAU,EAAEC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;MACzE,MAAMC,aAAa,GAAG,IAAI,CAACjE,OAAO,CAACS,UAAU,KAAK,IAAI,GAChD,IAAI,CAACyD,gBAAgB,CAACJ,cAAc,CAAC,GACrC,IAAI,CAACK,iBAAiB,CAACL,cAAc,CAAC,CAAA;AAE5C,MAAA,IAAIG,aAAa,EAAE;AACf,QAAA,IAAI,CAACJ,QAAQ,CAACF,IAAI,CAAC,CAAA;AACvB,OAAC,MAAM;AACH,QAAA,IAAI,CAACS,QAAQ,CAACT,IAAI,CAAC,CAAA;AACvB,OAAA;AACJ,KAAC,CAAC,CAAA;AAEF9D,IAAAA,UAAU,CAAC,MAAM;MACb,IAAI,CAAC+B,aAAa,EAAE,CAAA;AACxB,KAAC,EAAE,IAAI,CAAC5B,OAAO,CAACQ,iBAAiB,CAAC,CAAA;AACtC,GAAA;;AAEA;AACJ;AACA;AACA;AACA;AACA;EACI0D,gBAAgBA,CAACJ,cAAc,EAAE;IAC7B,OAAO,CAAC,GAAG,IAAI,CAAC1C,cAAc,CAAC,CAACiD,IAAI,CAACvB,MAAM,IAAI;MAC3C,MAAM,CAACwB,IAAI,EAAE5B,KAAK,CAAC,GAAGI,MAAM,CAACkB,KAAK,CAAC,GAAG,CAAC,CAAA;MACvC,OAAOF,cAAc,CAACF,GAAG,CAAC,GAAGU,IAAI,CAAA,CAAA,EAAI5B,KAAK,CAAA,CAAE,CAAC,CAAA;AACjD,KAAC,CAAC,CAAA;AACN,GAAA;;AAEA;AACJ;AACA;AACA;AACA;AACA;EACIyB,iBAAiBA,CAACL,cAAc,EAAE;IAC9B,OAAO,CAAC,GAAG,IAAI,CAAC1C,cAAc,CAAC,CAACmD,KAAK,CAACzB,MAAM,IAAI;MAC5C,MAAM,CAACwB,IAAI,EAAE5B,KAAK,CAAC,GAAGI,MAAM,CAACkB,KAAK,CAAC,GAAG,CAAC,CAAA;MACvC,OAAOF,cAAc,CAACF,GAAG,CAAC,GAAGU,IAAI,CAAA,CAAA,EAAI5B,KAAK,CAAA,CAAE,CAAC,CAAA;AACjD,KAAC,CAAC,CAAA;AACN,GAAA;;AAEA;AACJ;AACA;AACA;AACA;EACImB,QAAQA,CAACF,IAAI,EAAE;AACX,IAAA,IAAI,CAACpC,YAAY,CAAC+B,GAAG,CAACK,IAAI,CAAC,CAAA;IAC3BA,IAAI,CAACR,SAAS,CAACC,MAAM,CAAC,IAAI,CAACpD,OAAO,CAACO,WAAW,CAAC,CAAA;AAC/CoD,IAAAA,IAAI,CAACa,KAAK,CAACC,OAAO,GAAG,GAAG,CAAA;AACxBd,IAAAA,IAAI,CAACa,KAAK,CAACE,SAAS,GAAG,aAAa,CAAA;AAEpCf,IAAAA,IAAI,CAACgB,YAAY,CAAA;AAEjBC,IAAAA,qBAAqB,CAAC,MAAM;AACxBjB,MAAAA,IAAI,CAACa,KAAK,CAACC,OAAO,GAAG,GAAG,CAAA;AACxBd,MAAAA,IAAI,CAACa,KAAK,CAACE,SAAS,GAAG,UAAU,CAAA;AACrC,KAAC,CAAC,CAAA;AACN,GAAA;;AAEA;AACJ;AACA;AACA;AACA;EACIN,QAAQA,CAACT,IAAI,EAAE;AACXA,IAAAA,IAAI,CAACa,KAAK,CAACC,OAAO,GAAG,GAAG,CAAA;AACxBd,IAAAA,IAAI,CAACa,KAAK,CAACE,SAAS,GAAG,aAAa,CAAA;AAEpC7E,IAAAA,UAAU,CAAC,MAAM;AACb,MAAA,IAAI8D,IAAI,CAACa,KAAK,CAACC,OAAO,KAAK,GAAG,EAAE;QAC5Bd,IAAI,CAACR,SAAS,CAACG,GAAG,CAAC,IAAI,CAACtD,OAAO,CAACO,WAAW,CAAC,CAAA;AAC5C,QAAA,IAAI,CAACgB,YAAY,CAACiC,MAAM,CAACG,IAAI,CAAC,CAAA;AAClC,OAAA;AACJ,KAAC,EAAE,IAAI,CAAC3D,OAAO,CAACQ,iBAAiB,CAAC,CAAA;AACtC,GAAA;;AAEA;AACJ;AACA;AACA;AACA;EACIgC,MAAMA,CAACqC,KAAK,EAAE;IACV,IAAI,CAACvD,aAAa,GAAGuD,KAAK,CAACC,WAAW,EAAE,CAACC,IAAI,EAAE,CAAA;AAG/C,IAAA,IAAI,CAAChE,KAAK,CAACoB,OAAO,CAACwB,IAAI,IAAI;AACvB,MAAA,MAAMqB,UAAU,GAAG,IAAI,CAAChF,OAAO,CAACU,UAAU,CACrCuE,GAAG,CAACC,GAAG,IAAIvB,IAAI,CAACd,OAAO,CAACqC,GAAG,CAAC,IAAI,EAAE,CAAC,CACnCC,IAAI,CAAC,GAAG,CAAC,CACTL,WAAW,EAAE,CAAA;AAElB,MAAA,MAAMM,aAAa,GAAG,IAAI,CAAC9D,aAAa,KAAK,EAAE,IAC3C0D,UAAU,CAACK,QAAQ,CAAC,IAAI,CAAC/D,aAAa,CAAC,CAAA;AAE3C,MAAA,IAAI8D,aAAa,EAAE;AACf,QAAA,IAAI,CAACvB,QAAQ,CAACF,IAAI,CAAC,CAAA;AAEvB,OAAC,MAAM;AACH,QAAA,IAAI,CAACS,QAAQ,CAACT,IAAI,CAAC,CAAA;AACvB,OAAA;AACJ,KAAC,CAAC,CAAA;IAEF,IAAI,CAACV,SAAS,EAAE,CAAA;AAEhBpD,IAAAA,UAAU,CAAC,MAAM;MACb,IAAI,CAAC+B,aAAa,EAAE,CAAA;AACxB,KAAC,EAAE,IAAI,CAAC5B,OAAO,CAACQ,iBAAiB,CAAC,CAAA;AACtC,GAAA;;AAEA;AACJ;AACA;AACA;AACA;EACI8E,YAAYA,CAACC,QAAQ,EAAE;AACnB,IAAA,MAAMxE,KAAK,GAAG,CAAC,GAAG,IAAI,CAACA,KAAK,CAAC,CAAA;AAE7BA,IAAAA,KAAK,CAACyE,IAAI,CAAC,CAACC,CAAC,EAAEC,CAAC,KAAK;AACjB,MAAA,KAAK,MAAMC,SAAS,IAAIJ,QAAQ,EAAE;QAC9B,MAAMK,MAAM,GAAGH,CAAC,CAAC5C,OAAO,CAAC8C,SAAS,CAACT,GAAG,CAAC,CAAA;QACvC,MAAMW,MAAM,GAAGH,CAAC,CAAC7C,OAAO,CAAC8C,SAAS,CAACT,GAAG,CAAC,CAAA;QAEvC,MAAMY,UAAU,GAAGH,SAAS,CAACI,SAAS,KAAK,KAAK,GAC1CH,MAAM,CAACI,aAAa,CAACH,MAAM,CAAC,GAC5BA,MAAM,CAACG,aAAa,CAACJ,MAAM,CAAC,CAAA;AAElC,QAAA,IAAIE,UAAU,KAAK,CAAC,EAAE,OAAOA,UAAU,CAAA;AAC3C,OAAA;AACA,MAAA,OAAO,CAAC,CAAA;AACZ,KAAC,CAAC,CAAA;AAEF/E,IAAAA,KAAK,CAACoB,OAAO,CAACwB,IAAI,IAAI,IAAI,CAAC/C,SAAS,CAACsB,WAAW,CAACyB,IAAI,CAAC,CAAC,CAAA;AAC3D,GAAA;;AAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACIsC,EAAAA,cAAcA,CAACf,GAAG,EAAEgB,GAAG,EAAEC,GAAG,EAAE;AAC1B,IAAA,IAAI,CAACpF,KAAK,CAACoB,OAAO,CAACwB,IAAI,IAAI;MACvB,MAAMjB,KAAK,GAAG0D,UAAU,CAACzC,IAAI,CAACd,OAAO,CAACqC,GAAG,CAAC,CAAC,CAAA;MAC3C,MAAMmB,OAAO,GAAG3D,KAAK,IAAIwD,GAAG,IAAIxD,KAAK,IAAIyD,GAAG,CAAA;AAE5C,MAAA,IAAIE,OAAO,EAAE;AACT,QAAA,IAAI,CAACxC,QAAQ,CAACF,IAAI,CAAC,CAAA;AACvB,OAAC,MAAM;AACH,QAAA,IAAI,CAACS,QAAQ,CAACT,IAAI,CAAC,CAAA;AACvB,OAAA;AACJ,KAAC,CAAC,CAAA;AAEF9D,IAAAA,UAAU,CAAC,MAAM;MACb,IAAI,CAAC+B,aAAa,EAAE,CAAA;AACxB,KAAC,EAAE,IAAI,CAAC5B,OAAO,CAACQ,iBAAiB,CAAC,CAAA;AACtC,GAAA;;AAEA;AACJ;AACA;AACA;AACIyC,EAAAA,SAASA,GAAG;AACR,IAAA,MAAMqD,MAAM,GAAG,IAAIC,eAAe,EAAE,CAAA;;AAEpC;IACA,MAAMC,aAAa,GAAG,EAAE,CAAA;AACxB,IAAA,KAAK,MAAM1D,MAAM,IAAI,IAAI,CAAC1B,cAAc,EAAE;MACtC,IAAI0B,MAAM,KAAK,GAAG,EAAE;QAChB,MAAM,CAACwB,IAAI,EAAE5B,KAAK,CAAC,GAAGI,MAAM,CAACkB,KAAK,CAAC,GAAG,CAAC,CAAA;AACvC,QAAA,IAAI,CAACwC,aAAa,CAAClC,IAAI,CAAC,EAAE;AACtBkC,UAAAA,aAAa,CAAClC,IAAI,CAAC,GAAG,IAAIjD,GAAG,EAAE,CAAA;AACnC,SAAA;AACAmF,QAAAA,aAAa,CAAClC,IAAI,CAAC,CAAChB,GAAG,CAACZ,KAAK,CAAC,CAAA;AAClC,OAAA;AACJ,KAAA;;AAEA;AACA+D,IAAAA,MAAM,CAACC,OAAO,CAACF,aAAa,CAAC,CAACrE,OAAO,CAAC,CAAC,CAACmC,IAAI,EAAEqC,MAAM,CAAC,KAAK;AACtDL,MAAAA,MAAM,CAACM,GAAG,CAACtC,IAAI,EAAEuC,KAAK,CAACC,IAAI,CAACH,MAAM,CAAC,CAACxB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AAClD,KAAC,CAAC,CAAA;IAEF,IAAI,IAAI,CAAC7D,aAAa,EAAE;MACpBgF,MAAM,CAACM,GAAG,CAAC,QAAQ,EAAE,IAAI,CAACtF,aAAa,CAAC,CAAA;AAC5C,KAAA;IAEA,MAAMyF,MAAM,GAAG,CAAA,EAAGpE,MAAM,CAACqE,QAAQ,CAACC,QAAQ,CAAGX,EAAAA,MAAM,CAACY,QAAQ,EAAE,GAAG,GAAG,GAAGZ,MAAM,CAACY,QAAQ,EAAE,GAAG,EAAE,CAAE,CAAA,CAAA;IAC/FvE,MAAM,CAACwE,OAAO,CAACC,SAAS,CAAC,EAAE,EAAE,EAAE,EAAEL,MAAM,CAAC,CAAA;AAC5C,GAAA;;AAEA;AACJ;AACA;AACA;AACIpF,EAAAA,WAAWA,GAAG;IACV,MAAM2E,MAAM,GAAG,IAAIC,eAAe,CAAC5D,MAAM,CAACqE,QAAQ,CAACxE,MAAM,CAAC,CAAA;AAC1D,IAAA,IAAI,CAACpB,cAAc,CAACiC,KAAK,EAAE,CAAA;;AAE3B;IACA,IAAIgE,UAAU,GAAG,KAAK,CAAA;;AAEtB;AACA,IAAA,KAAK,MAAM,CAAC/C,IAAI,EAAEqC,MAAM,CAAC,IAAIL,MAAM,CAACI,OAAO,EAAE,EAAE;MAC3C,IAAIpC,IAAI,KAAK,QAAQ,EAAE;AACnB+C,QAAAA,UAAU,GAAG,IAAI,CAAA;QACjBV,MAAM,CAAC3C,KAAK,CAAC,GAAG,CAAC,CAAC7B,OAAO,CAACO,KAAK,IAAI;UAC/B,IAAI,CAACtB,cAAc,CAACkC,GAAG,CAAC,GAAGgB,IAAI,CAAA,CAAA,EAAI5B,KAAK,CAAA,CAAE,CAAC,CAAA;AAC/C,SAAC,CAAC,CAAA;AACN,OAAA;AACJ,KAAA;IAEA,IAAI,CAAC2E,UAAU,EAAE;AACb,MAAA,IAAI,CAACjG,cAAc,CAACkC,GAAG,CAAC,GAAG,CAAC,CAAA;AAChC,KAAA;;AAEA;AACA,IAAA,IAAI,CAACrC,aAAa,CAACkB,OAAO,CAACC,MAAM,IAAI;AACjC,MAAA,MAAMQ,WAAW,GAAGR,MAAM,CAACS,OAAO,CAACC,MAAM,CAAA;MACzC,IAAI,IAAI,CAAC1B,cAAc,CAACwC,GAAG,CAAChB,WAAW,CAAC,IACnCA,WAAW,KAAK,GAAG,IAAI,IAAI,CAACxB,cAAc,CAACwC,GAAG,CAAC,GAAG,CAAE,EAAE;QACvDxB,MAAM,CAACe,SAAS,CAACG,GAAG,CAAC,IAAI,CAACtD,OAAO,CAACM,WAAW,CAAC,CAAA;AAClD,OAAC,MAAM;QACH8B,MAAM,CAACe,SAAS,CAACC,MAAM,CAAC,IAAI,CAACpD,OAAO,CAACM,WAAW,CAAC,CAAA;AACrD,OAAA;AACJ,KAAC,CAAC,CAAA;;AAEF;IACA,MAAMkC,MAAM,GAAG8D,MAAM,CAACgB,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAA;IACzC,IAAI,IAAI,CAACpG,WAAW,EAAE;AAClB,MAAA,IAAI,CAACA,WAAW,CAACwB,KAAK,GAAGF,MAAM,CAAA;AACnC,KAAA;IAEA,IAAI,CAACM,MAAM,EAAE,CAAA;AACb,IAAA,IAAIN,MAAM,EAAE;AACR,MAAA,IAAI,CAACA,MAAM,CAACA,MAAM,CAAC,CAAA;AACvB,KAAA;AACJ,GAAA;;AAEA;AACJ;AACA;AACA;AACA;AACIZ,EAAAA,aAAaA,GAAG;AACZ,IAAA,MAAM2F,KAAK,GAAG,IAAI,CAACxG,KAAK,CAACyG,MAAM,CAAA;AAC/B,IAAA,MAAMC,OAAO,GAAG,IAAI,CAAClG,YAAY,CAACmC,IAAI,CAAA;IAEtC,IAAI,IAAI,CAACvC,OAAO,EAAE;MACd,IAAI,CAACA,OAAO,CAACa,WAAW,GAAG,CAAWyF,QAAAA,EAAAA,OAAO,CAAOF,IAAAA,EAAAA,KAAK,CAAE,CAAA,CAAA;AAC/D,KAAA;IAEA,OAAO;MAAEA,KAAK;AAAEE,MAAAA,OAAAA;KAAS,CAAA;AAC7B,GAAA;;AAEA;AACJ;AACA;AACA;AACA;EACIC,aAAaA,CAACC,IAAI,EAAE;AAChB,IAAA,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAACtC,QAAQ,CAACsC,IAAI,CAACC,WAAW,EAAE,CAAC,EAAE;MAC5C,IAAI,CAAC5H,OAAO,CAACS,UAAU,GAAGkH,IAAI,CAACC,WAAW,EAAE,CAAA;MAC5C,IAAI,CAAC9E,MAAM,EAAE,CAAA;AACjB,KAAA;AACJ,GAAA;;AAEA;AACJ;AACA;AACA;AACA;AACA;AACI+E,EAAAA,SAASA,CAACvD,IAAI,EAAE5B,KAAK,EAAE;IACnB,IAAI,CAACtB,cAAc,CAACkC,GAAG,CAAC,GAAGgB,IAAI,CAAA,CAAA,EAAI5B,KAAK,CAAA,CAAE,CAAC,CAAA;IAC3C,IAAI,CAACI,MAAM,EAAE,CAAA;IACb,IAAI,CAACG,SAAS,EAAE,CAAA;AACpB,GAAA;;AAEA;AACJ;AACA;AACA;AACA;AACI6E,EAAAA,YAAYA,CAACxD,IAAI,EAAE5B,KAAK,EAAE;IACtB,IAAI,CAACtB,cAAc,CAACoC,MAAM,CAAC,GAAGc,IAAI,CAAA,CAAA,EAAI5B,KAAK,CAAA,CAAE,CAAC,CAAA;AAC9C,IAAA,IAAI,IAAI,CAACtB,cAAc,CAACsC,IAAI,KAAK,CAAC,EAAE;AAChC,MAAA,IAAI,CAACtC,cAAc,CAACkC,GAAG,CAAC,GAAG,CAAC,CAAA;AAChC,KAAA;IACA,IAAI,CAACR,MAAM,EAAE,CAAA;IACb,IAAI,CAACG,SAAS,EAAE,CAAA;AACpB,GAAA;;AAEA;AACJ;AACA;AACA;AACA;EACI8E,sBAAsBA,CAACzD,IAAI,EAAE;AACzB,IAAA,OAAO,CAAC,GAAG,IAAI,CAAClD,cAAc,CAAC,CAC1B0B,MAAM,CAACA,MAAM,IAAIA,MAAM,CAACkF,UAAU,CAAC,CAAG1D,EAAAA,IAAI,CAAG,CAAA,CAAA,CAAC,CAAC,CAC/CW,GAAG,CAACnC,MAAM,IAAIA,MAAM,CAACkB,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAC5C,GAAA;AACJ;;;;"}