advanced-filter-system 1.0.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.
@@ -0,0 +1,492 @@
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() {
24
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
25
+ args[_key] = arguments[_key];
26
+ }
27
+ const later = () => {
28
+ clearTimeout(timeout);
29
+ func(...args);
30
+ };
31
+ clearTimeout(timeout);
32
+ timeout = setTimeout(later, wait);
33
+ };
34
+ }
35
+ class AFS {
36
+ /**
37
+ * @typedef {Object} FilterOptions
38
+ * @property {string} containerSelector - Main container selector
39
+ * @property {string} itemSelector - Items to filter selector
40
+ * @property {string} filterButtonSelector - Filter buttons selector
41
+ * @property {string} [searchInputSelector] - Search input selector
42
+ * @property {string} [counterSelector] - Results counter selector
43
+ * @property {string} [activeClass='active'] - Active state class
44
+ * @property {string} [hiddenClass='hidden'] - Hidden state class
45
+ * @property {number} [animationDuration=300] - Animation duration in ms
46
+ * @property {string} [filterMode='OR'] - Filter mode ('OR' or 'AND')
47
+ * @property {string[]} [searchKeys=['title']] - Data attributes to search in
48
+ * @property {number} [debounceTime=300] - Search debounce delay in ms
49
+ */
50
+
51
+ /**
52
+ * @param {FilterOptions} options - Filter configuration options
53
+ */
54
+ constructor() {
55
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
56
+ this.options = {
57
+ containerSelector: ".filter-container",
58
+ itemSelector: ".filter-item",
59
+ filterButtonSelector: ".btn-filter",
60
+ searchInputSelector: ".filter-search",
61
+ counterSelector: ".filter-counter",
62
+ activeClass: "active",
63
+ hiddenClass: "hidden",
64
+ animationDuration: 300,
65
+ filterMode: "OR",
66
+ searchKeys: ["title"],
67
+ debounceTime: 300,
68
+ ...options
69
+ };
70
+
71
+ // Initialize elements
72
+ this.container = document.querySelector(this.options.containerSelector);
73
+ this.items = document.querySelectorAll(this.options.itemSelector);
74
+ this.filterButtons = document.querySelectorAll(this.options.filterButtonSelector);
75
+ this.searchInput = document.querySelector(this.options.searchInputSelector);
76
+ this.counter = document.querySelector(this.options.counterSelector);
77
+
78
+ // Initialize state
79
+ this.currentFilters = new Set(["*"]);
80
+ this.currentSearch = "";
81
+ this.visibleItems = new Set(this.items);
82
+ this.init();
83
+ }
84
+
85
+ /**
86
+ * Initialize the filter system
87
+ * @private
88
+ */
89
+ init() {
90
+ this.addStyles();
91
+ this.bindEvents();
92
+ this.loadFromURL();
93
+ this.updateCounter();
94
+ }
95
+
96
+ /**
97
+ * Add required styles to document
98
+ * @private
99
+ */
100
+ addStyles() {
101
+ const styles = `
102
+ .${this.options.hiddenClass} {
103
+ display: none !important;
104
+ }
105
+
106
+ ${this.options.itemSelector} {
107
+ opacity: 1;
108
+ transform: scale(1);
109
+ transition: opacity ${this.options.animationDuration}ms ease-out,
110
+ transform ${this.options.animationDuration}ms ease-out;
111
+ }
112
+
113
+ ${this.options.filterButtonSelector} {
114
+ opacity: 0.5;
115
+ transition: opacity ${this.options.animationDuration}ms ease;
116
+ }
117
+
118
+ ${this.options.filterButtonSelector}.${this.options.activeClass} {
119
+ opacity: 1;
120
+ }
121
+ `;
122
+ const styleSheet = document.createElement("style");
123
+ styleSheet.textContent = styles;
124
+ document.head.appendChild(styleSheet);
125
+ }
126
+
127
+ /**
128
+ * Bind all event listeners
129
+ * @private
130
+ */
131
+ bindEvents() {
132
+ this.filterButtons.forEach(button => {
133
+ button.addEventListener("click", () => this.handleFilterClick(button));
134
+ });
135
+ if (this.searchInput) {
136
+ this.searchInput.addEventListener("input", debounce(e => {
137
+ this.search(e.target.value);
138
+ }, this.options.debounceTime));
139
+ }
140
+ window.addEventListener("popstate", () => this.loadFromURL());
141
+ }
142
+
143
+ /**
144
+ * Handle filter button clicks
145
+ * @private
146
+ * @param {HTMLElement} button - Clicked filter button
147
+ */
148
+ handleFilterClick(button) {
149
+ const filterValue = button.dataset.filter;
150
+ if (filterValue === "*") {
151
+ this.resetFilters();
152
+ } else {
153
+ this.toggleFilter(filterValue, button);
154
+ }
155
+ this.filter();
156
+ this.updateURL();
157
+ }
158
+
159
+ /**
160
+ * Reset all filters to default state
161
+ * @private
162
+ */
163
+ resetFilters() {
164
+ this.filterButtons.forEach(btn => btn.classList.remove(this.options.activeClass));
165
+ this.currentFilters.clear();
166
+ this.currentFilters.add("*");
167
+ this.filterButtons[0].classList.add(this.options.activeClass);
168
+ this.resetCounter();
169
+ }
170
+
171
+ /**
172
+ * Reset visible items counter
173
+ * @private
174
+ */
175
+ resetCounter() {
176
+ this.visibleItems = new Set(this.items);
177
+ this.updateCounter();
178
+ }
179
+
180
+ /**
181
+ * Toggle individual filter state
182
+ * @private
183
+ * @param {string} filterValue - Filter value to toggle
184
+ * @param {HTMLElement} button - Filter button element
185
+ */
186
+ toggleFilter(filterValue, button) {
187
+ this.currentFilters.delete("*");
188
+ this.filterButtons[0].classList.remove(this.options.activeClass);
189
+ if (button.classList.contains(this.options.activeClass)) {
190
+ button.classList.remove(this.options.activeClass);
191
+ this.currentFilters.delete(filterValue);
192
+ if (this.currentFilters.size === 0) {
193
+ this.resetFilters();
194
+ }
195
+ } else {
196
+ button.classList.add(this.options.activeClass);
197
+ this.currentFilters.add(filterValue);
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Apply current filters to items
203
+ * @public
204
+ */
205
+ filter() {
206
+ this.visibleItems.clear(); // Start with an empty set
207
+
208
+ this.items.forEach(item => {
209
+ if (this.currentFilters.has("*")) {
210
+ this.showItem(item);
211
+ this.visibleItems.add(item); // Add visible item to the set
212
+ } else {
213
+ const itemCategories = new Set(item.dataset.categories?.split(" ") || []);
214
+ const matchesFilter = this.options.filterMode === "OR" ? this.matchesAnyFilter(itemCategories) : this.matchesAllFilters(itemCategories);
215
+ if (matchesFilter) {
216
+ this.showItem(item);
217
+ this.visibleItems.add(item); // Add visible item to the set
218
+ } else {
219
+ this.hideItem(item);
220
+ }
221
+ }
222
+ });
223
+ setTimeout(() => {
224
+ this.updateCounter();
225
+ }, this.options.animationDuration);
226
+ }
227
+
228
+ /**
229
+ * Check if item matches any active filter (OR mode)
230
+ * @private
231
+ * @param {Set} itemCategories - Item's categories
232
+ * @returns {boolean} Whether item matches any filter
233
+ */
234
+ matchesAnyFilter(itemCategories) {
235
+ return [...this.currentFilters].some(filter => {
236
+ const [type, value] = filter.split(":");
237
+ return itemCategories.has(`${type}:${value}`);
238
+ });
239
+ }
240
+
241
+ /**
242
+ * Check if item matches all active filters (AND mode)
243
+ * @private
244
+ * @param {Set} itemCategories - Item's categories
245
+ * @returns {boolean} Whether item matches all filters
246
+ */
247
+ matchesAllFilters(itemCategories) {
248
+ return [...this.currentFilters].every(filter => {
249
+ const [type, value] = filter.split(":");
250
+ return itemCategories.has(`${type}:${value}`);
251
+ });
252
+ }
253
+
254
+ /**
255
+ * Show an item with animation
256
+ * @private
257
+ * @param {HTMLElement} item - Item to show
258
+ */
259
+ showItem(item) {
260
+ this.visibleItems.add(item);
261
+ item.classList.remove(this.options.hiddenClass);
262
+ item.style.opacity = "0";
263
+ item.style.transform = "scale(0.95)";
264
+ item.offsetHeight;
265
+ requestAnimationFrame(() => {
266
+ item.style.opacity = "1";
267
+ item.style.transform = "scale(1)";
268
+ });
269
+ }
270
+
271
+ /**
272
+ * Hide an item with animation
273
+ * @private
274
+ * @param {HTMLElement} item - Item to hide
275
+ */
276
+ hideItem(item) {
277
+ item.style.opacity = "0";
278
+ item.style.transform = "scale(0.95)";
279
+ setTimeout(() => {
280
+ if (item.style.opacity === "0") {
281
+ item.classList.add(this.options.hiddenClass);
282
+ this.visibleItems.delete(item);
283
+ }
284
+ }, this.options.animationDuration);
285
+ }
286
+
287
+ /**
288
+ * Search items by text
289
+ * @public
290
+ * @param {string} query - Search query
291
+ */
292
+ search(query) {
293
+ this.currentSearch = query.toLowerCase().trim();
294
+ this.items.forEach(item => {
295
+ const searchText = this.options.searchKeys.map(key => item.dataset[key] || "").join(" ").toLowerCase();
296
+ const matchesSearch = this.currentSearch === "" || searchText.includes(this.currentSearch);
297
+ if (matchesSearch) {
298
+ this.showItem(item);
299
+ } else {
300
+ this.hideItem(item);
301
+ }
302
+ });
303
+ this.updateURL();
304
+ setTimeout(() => {
305
+ this.updateCounter();
306
+ }, this.options.animationDuration);
307
+ }
308
+
309
+ /**
310
+ * Sort items by multiple criteria
311
+ * @public
312
+ * @param {Array<{key: string, direction: string}>} criteria - Sort criteria
313
+ */
314
+ sortMultiple(criteria) {
315
+ const items = [...this.items];
316
+ items.sort((a, b) => {
317
+ for (const criterion of criteria) {
318
+ const valueA = a.dataset[criterion.key];
319
+ const valueB = b.dataset[criterion.key];
320
+ const comparison = criterion.direction === "asc" ? valueA.localeCompare(valueB) : valueB.localeCompare(valueA);
321
+ if (comparison !== 0) return comparison;
322
+ }
323
+ return 0;
324
+ });
325
+ items.forEach(item => this.container.appendChild(item));
326
+ }
327
+
328
+ /**
329
+ * Filter items by numeric range
330
+ * @public
331
+ * @param {string} key - Data attribute key
332
+ * @param {number} min - Minimum value
333
+ * @param {number} max - Maximum value
334
+ */
335
+ addRangeFilter(key, min, max) {
336
+ this.items.forEach(item => {
337
+ const value = parseFloat(item.dataset[key]);
338
+ const inRange = value >= min && value <= max;
339
+ if (inRange) {
340
+ this.showItem(item);
341
+ } else {
342
+ this.hideItem(item);
343
+ }
344
+ });
345
+ setTimeout(() => {
346
+ this.updateCounter();
347
+ }, this.options.animationDuration);
348
+ }
349
+
350
+ /**
351
+ * Update URL with current filter state
352
+ * @private
353
+ */
354
+ updateURL() {
355
+ const params = new URLSearchParams();
356
+
357
+ // Séparer les filtres par type
358
+ const filtersByType = {};
359
+ for (const filter of this.currentFilters) {
360
+ if (filter !== "*") {
361
+ const [type, value] = filter.split(":");
362
+ if (!filtersByType[type]) {
363
+ filtersByType[type] = new Set();
364
+ }
365
+ filtersByType[type].add(value);
366
+ }
367
+ }
368
+
369
+ // Ajouter chaque type de filtre à l'URL
370
+ Object.entries(filtersByType).forEach(_ref => {
371
+ let [type, values] = _ref;
372
+ params.set(type, Array.from(values).join(","));
373
+ });
374
+ if (this.currentSearch) {
375
+ params.set("search", this.currentSearch);
376
+ }
377
+ const newURL = `${window.location.pathname}${params.toString() ? "?" + params.toString() : ""}`;
378
+ window.history.pushState({}, "", newURL);
379
+ }
380
+
381
+ /**
382
+ * Load filter state from URL
383
+ * @private
384
+ */
385
+ loadFromURL() {
386
+ const params = new URLSearchParams(window.location.search);
387
+ this.currentFilters.clear();
388
+
389
+ // Si aucun filtre n'est présent, utiliser '*'
390
+ let hasFilters = false;
391
+
392
+ // Parcourir tous les paramètres
393
+ for (const [type, values] of params.entries()) {
394
+ if (type !== "search") {
395
+ hasFilters = true;
396
+ values.split(",").forEach(value => {
397
+ this.currentFilters.add(`${type}:${value}`);
398
+ });
399
+ }
400
+ }
401
+ if (!hasFilters) {
402
+ this.currentFilters.add("*");
403
+ }
404
+
405
+ // Update active buttons
406
+ this.filterButtons.forEach(button => {
407
+ const filterValue = button.dataset.filter;
408
+ if (this.currentFilters.has(filterValue) || filterValue === "*" && this.currentFilters.has("*")) {
409
+ button.classList.add(this.options.activeClass);
410
+ } else {
411
+ button.classList.remove(this.options.activeClass);
412
+ }
413
+ });
414
+
415
+ // Load search
416
+ const search = params.get("search") || "";
417
+ if (this.searchInput) {
418
+ this.searchInput.value = search;
419
+ }
420
+ this.filter();
421
+ if (search) {
422
+ this.search(search);
423
+ }
424
+ }
425
+
426
+ /**
427
+ * Update results counter
428
+ * @private
429
+ * @returns {{total: number, visible: number}}
430
+ */
431
+ updateCounter() {
432
+ const total = this.items.length;
433
+ const visible = this.visibleItems.size;
434
+ if (this.counter) {
435
+ this.counter.textContent = `Showing ${visible} of ${total}`;
436
+ }
437
+ return {
438
+ total,
439
+ visible
440
+ };
441
+ }
442
+
443
+ /**
444
+ * Change filter mode
445
+ * @public
446
+ * @param {string} mode - New filter mode ('OR' or 'AND')
447
+ */
448
+ setFilterMode(mode) {
449
+ if (["OR", "AND"].includes(mode.toUpperCase())) {
450
+ this.options.filterMode = mode.toUpperCase();
451
+ this.filter();
452
+ }
453
+ }
454
+
455
+ /**
456
+ * Add filter by type and value
457
+ * @public
458
+ * @param {string} type - Filter type
459
+ * @param {string} value - Filter value
460
+ */
461
+ addFilter(type, value) {
462
+ this.currentFilters.add(`${type}:${value}`);
463
+ this.filter();
464
+ this.updateURL();
465
+ }
466
+
467
+ /**
468
+ * Remove filter by type and value
469
+ * @public
470
+ * @param {string} type - Filter type
471
+ */
472
+ removeFilter(type, value) {
473
+ this.currentFilters.delete(`${type}:${value}`);
474
+ if (this.currentFilters.size === 0) {
475
+ this.currentFilters.add("*");
476
+ }
477
+ this.filter();
478
+ this.updateURL();
479
+ }
480
+
481
+ /**
482
+ * Get active filters by type
483
+ * @public
484
+ * @param {string} type - Filter type
485
+ */
486
+ getActiveFiltersByType(type) {
487
+ return [...this.currentFilters].filter(filter => filter.startsWith(`${type}:`)).map(filter => filter.split(":")[1]);
488
+ }
489
+ }
490
+
491
+ export { AFS };
492
+ //# sourceMappingURL=AFS.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AFS.esm.js","sources":["../src/AFS.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 AFS {\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(\n this.options.filterButtonSelector,\n );\n this.searchInput = document.querySelector(\n this.options.searchInputSelector,\n );\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\", () =>\n this.handleFilterClick(button),\n );\n });\n\n if (this.searchInput) {\n this.searchInput.addEventListener(\n \"input\",\n debounce((e) => {\n this.search(e.target.value);\n }, this.options.debounceTime),\n );\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) =>\n btn.classList.remove(this.options.activeClass),\n );\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.visibleItems.clear(); // Start with an empty set\n\n this.items.forEach((item) => {\n if (this.currentFilters.has(\"*\")) {\n this.showItem(item);\n this.visibleItems.add(item); // Add visible item to the set\n } else {\n const itemCategories = new Set(\n item.dataset.categories?.split(\" \") || [],\n );\n const matchesFilter =\n this.options.filterMode === \"OR\"\n ? this.matchesAnyFilter(itemCategories)\n : this.matchesAllFilters(itemCategories);\n\n if (matchesFilter) {\n this.showItem(item);\n this.visibleItems.add(item); // Add visible item to the set\n } else {\n this.hideItem(item);\n }\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 =\n 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 =\n 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}${\n params.toString() ? \"?\" + params.toString() : \"\"\n }`;\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 (\n this.currentFilters.has(filterValue) ||\n (filterValue === \"*\" && this.currentFilters.has(\"*\"))\n ) {\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 { AFS };\n"],"names":["debounce","func","wait","timeout","executedFunction","_len","arguments","length","args","Array","_key","later","clearTimeout","setTimeout","AFS","constructor","options","undefined","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","_ref","values","set","from","newURL","location","pathname","toString","history","pushState","hasFilters","get","total","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;EACX,OAAO,SAASC,gBAAgBA,GAAU;AAAA,IAAA,KAAA,IAAAC,IAAA,GAAAC,SAAA,CAAAC,MAAA,EAANC,IAAI,GAAAC,IAAAA,KAAA,CAAAJ,IAAA,GAAAK,IAAA,GAAA,CAAA,EAAAA,IAAA,GAAAL,IAAA,EAAAK,IAAA,EAAA,EAAA;AAAJF,MAAAA,IAAI,CAAAE,IAAA,CAAAJ,GAAAA,SAAA,CAAAI,IAAA,CAAA,CAAA;AAAA,KAAA;IACpC,MAAMC,KAAK,GAAGA,MAAM;MAChBC,YAAY,CAACT,OAAO,CAAC,CAAA;MACrBF,IAAI,CAAC,GAAGO,IAAI,CAAC,CAAA;KAChB,CAAA;IACDI,YAAY,CAACT,OAAO,CAAC,CAAA;AACrBA,IAAAA,OAAO,GAAGU,UAAU,CAACF,KAAK,EAAET,IAAI,CAAC,CAAA;GACpC,CAAA;AACL,CAAA;AAEA,MAAMY,GAAG,CAAC;AACN;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEI;AACJ;AACA;AACIC,EAAAA,WAAWA,GAAe;AAAA,IAAA,IAAdC,OAAO,GAAAV,SAAA,CAAAC,MAAA,GAAA,CAAA,IAAAD,SAAA,CAAA,CAAA,CAAA,KAAAW,SAAA,GAAAX,SAAA,CAAA,CAAA,CAAA,GAAG,EAAE,CAAA;IACpB,IAAI,CAACU,OAAO,GAAG;AACXE,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,GAAGZ,OAAAA;KACN,CAAA;;AAED;AACA,IAAA,IAAI,CAACa,SAAS,GAAGC,QAAQ,CAACC,aAAa,CAAC,IAAI,CAACf,OAAO,CAACE,iBAAiB,CAAC,CAAA;AACvE,IAAA,IAAI,CAACc,KAAK,GAAGF,QAAQ,CAACG,gBAAgB,CAAC,IAAI,CAACjB,OAAO,CAACG,YAAY,CAAC,CAAA;AACjE,IAAA,IAAI,CAACe,aAAa,GAAGJ,QAAQ,CAACG,gBAAgB,CAC1C,IAAI,CAACjB,OAAO,CAACI,oBACjB,CAAC,CAAA;AACD,IAAA,IAAI,CAACe,WAAW,GAAGL,QAAQ,CAACC,aAAa,CACrC,IAAI,CAACf,OAAO,CAACK,mBACjB,CAAC,CAAA;AACD,IAAA,IAAI,CAACe,OAAO,GAAGN,QAAQ,CAACC,aAAa,CAAC,IAAI,CAACf,OAAO,CAACM,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,CAAC9B,OAAO,CAACQ,WAAW,CAAA;AACvC;AACA;AACA;AACA,YAAA,EAAc,IAAI,CAACR,OAAO,CAACG,YAAY,CAAA;AACvC;AACA;AACA,oCAAA,EAAsC,IAAI,CAACH,OAAO,CAACS,iBAAiB,CAAA;AACpE,sCAAA,EAAwC,IAAI,CAACT,OAAO,CAACS,iBAAiB,CAAA;AACtE;AACA;AACA,YAAA,EAAc,IAAI,CAACT,OAAO,CAACI,oBAAoB,CAAA;AAC/C;AACA,oCAAA,EAAsC,IAAI,CAACJ,OAAO,CAACS,iBAAiB,CAAA;AACpE;AACA;AACA,YAAc,EAAA,IAAI,CAACT,OAAO,CAACI,oBAAoB,IAAI,IAAI,CAACJ,OAAO,CAACO,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,CAAEC,MAAM,IAAK;AACnCA,MAAAA,MAAM,CAACC,gBAAgB,CAAC,OAAO,EAAE,MAC7B,IAAI,CAACC,iBAAiB,CAACF,MAAM,CACjC,CAAC,CAAA;AACL,KAAC,CAAC,CAAA;IAEF,IAAI,IAAI,CAAClB,WAAW,EAAE;MAClB,IAAI,CAACA,WAAW,CAACmB,gBAAgB,CAC7B,OAAO,EACPtD,QAAQ,CAAEwD,CAAC,IAAK;QACZ,IAAI,CAACC,MAAM,CAACD,CAAC,CAACE,MAAM,CAACC,KAAK,CAAC,CAAA;AAC/B,OAAC,EAAE,IAAI,CAAC3C,OAAO,CAACY,YAAY,CAChC,CAAC,CAAA;AACL,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,CAAEe,GAAG,IAC3BA,GAAG,CAACC,SAAS,CAACC,MAAM,CAAC,IAAI,CAACrD,OAAO,CAACO,WAAW,CACjD,CAAC,CAAA;AACD,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,CAACvD,OAAO,CAACO,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,CAACrD,OAAO,CAACO,WAAW,CAAC,CAAA;AAEhE,IAAA,IAAI8B,MAAM,CAACe,SAAS,CAACM,QAAQ,CAAC,IAAI,CAAC1D,OAAO,CAACO,WAAW,CAAC,EAAE;MACrD8B,MAAM,CAACe,SAAS,CAACC,MAAM,CAAC,IAAI,CAACrD,OAAO,CAACO,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,CAACvD,OAAO,CAACO,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,CAACvB,YAAY,CAAC8B,KAAK,EAAE,CAAC;;AAE1B,IAAA,IAAI,CAACtC,KAAK,CAACoB,OAAO,CAAEwB,IAAI,IAAK;MACzB,IAAI,IAAI,CAACvC,cAAc,CAACwC,GAAG,CAAC,GAAG,CAAC,EAAE;AAC9B,QAAA,IAAI,CAACC,QAAQ,CAACF,IAAI,CAAC,CAAA;QACnB,IAAI,CAACpC,YAAY,CAAC+B,GAAG,CAACK,IAAI,CAAC,CAAC;AAChC,OAAC,MAAM;AACH,QAAA,MAAMG,cAAc,GAAG,IAAIzC,GAAG,CAC1BsC,IAAI,CAACd,OAAO,CAACkB,UAAU,EAAEC,KAAK,CAAC,GAAG,CAAC,IAAI,EAC3C,CAAC,CAAA;QACD,MAAMC,aAAa,GACf,IAAI,CAAClE,OAAO,CAACU,UAAU,KAAK,IAAI,GAC1B,IAAI,CAACyD,gBAAgB,CAACJ,cAAc,CAAC,GACrC,IAAI,CAACK,iBAAiB,CAACL,cAAc,CAAC,CAAA;AAEhD,QAAA,IAAIG,aAAa,EAAE;AACf,UAAA,IAAI,CAACJ,QAAQ,CAACF,IAAI,CAAC,CAAA;UACnB,IAAI,CAACpC,YAAY,CAAC+B,GAAG,CAACK,IAAI,CAAC,CAAC;AAChC,SAAC,MAAM;AACH,UAAA,IAAI,CAACS,QAAQ,CAACT,IAAI,CAAC,CAAA;AACvB,SAAA;AACJ,OAAA;AACJ,KAAC,CAAC,CAAA;AAEF/D,IAAAA,UAAU,CAAC,MAAM;MACb,IAAI,CAACgC,aAAa,EAAE,CAAA;AACxB,KAAC,EAAE,IAAI,CAAC7B,OAAO,CAACS,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,CAAEvB,MAAM,IAAK;MAC7C,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,CAAEzB,MAAM,IAAK;MAC9C,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,CAACrD,OAAO,CAACQ,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;AAEpC9E,IAAAA,UAAU,CAAC,MAAM;AACb,MAAA,IAAI+D,IAAI,CAACa,KAAK,CAACC,OAAO,KAAK,GAAG,EAAE;QAC5Bd,IAAI,CAACR,SAAS,CAACG,GAAG,CAAC,IAAI,CAACvD,OAAO,CAACQ,WAAW,CAAC,CAAA;AAC5C,QAAA,IAAI,CAACgB,YAAY,CAACiC,MAAM,CAACG,IAAI,CAAC,CAAA;AAClC,OAAA;AACJ,KAAC,EAAE,IAAI,CAAC5D,OAAO,CAACS,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,CAAEwB,IAAI,IAAK;AACzB,MAAA,MAAMqB,UAAU,GAAG,IAAI,CAACjF,OAAO,CAACW,UAAU,CACrCuE,GAAG,CAAEC,GAAG,IAAKvB,IAAI,CAACd,OAAO,CAACqC,GAAG,CAAC,IAAI,EAAE,CAAC,CACrCC,IAAI,CAAC,GAAG,CAAC,CACTL,WAAW,EAAE,CAAA;AAElB,MAAA,MAAMM,aAAa,GACf,IAAI,CAAC9D,aAAa,KAAK,EAAE,IACzB0D,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;AAEhBrD,IAAAA,UAAU,CAAC,MAAM;MACb,IAAI,CAACgC,aAAa,EAAE,CAAA;AACxB,KAAC,EAAE,IAAI,CAAC7B,OAAO,CAACS,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,GACZH,SAAS,CAACI,SAAS,KAAK,KAAK,GACvBH,MAAM,CAACI,aAAa,CAACH,MAAM,CAAC,GAC5BA,MAAM,CAACG,aAAa,CAACJ,MAAM,CAAC,CAAA;AAEtC,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,CAAEwB,IAAI,IAAK,IAAI,CAAC/C,SAAS,CAACsB,WAAW,CAACyB,IAAI,CAAC,CAAC,CAAA;AAC7D,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,CAAEwB,IAAI,IAAK;MACzB,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;AAEF/D,IAAAA,UAAU,CAAC,MAAM;MACb,IAAI,CAACgC,aAAa,EAAE,CAAA;AACxB,KAAC,EAAE,IAAI,CAAC7B,OAAO,CAACS,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;IACA+D,MAAM,CAACC,OAAO,CAACF,aAAa,CAAC,CAACrE,OAAO,CAACwE,IAAA,IAAoB;AAAA,MAAA,IAAnB,CAACrC,IAAI,EAAEsC,MAAM,CAAC,GAAAD,IAAA,CAAA;AACjDL,MAAAA,MAAM,CAACO,GAAG,CAACvC,IAAI,EAAE9E,KAAK,CAACsH,IAAI,CAACF,MAAM,CAAC,CAACzB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AAClD,KAAC,CAAC,CAAA;IAEF,IAAI,IAAI,CAAC7D,aAAa,EAAE;MACpBgF,MAAM,CAACO,GAAG,CAAC,QAAQ,EAAE,IAAI,CAACvF,aAAa,CAAC,CAAA;AAC5C,KAAA;IAEA,MAAMyF,MAAM,GAAG,CAAA,EAAGpE,MAAM,CAACqE,QAAQ,CAACC,QAAQ,CACtCX,EAAAA,MAAM,CAACY,QAAQ,EAAE,GAAG,GAAG,GAAGZ,MAAM,CAACY,QAAQ,EAAE,GAAG,EAAE,CAClD,CAAA,CAAA;IACFvE,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,EAAEsC,MAAM,CAAC,IAAIN,MAAM,CAACI,OAAO,EAAE,EAAE;MAC3C,IAAIpC,IAAI,KAAK,QAAQ,EAAE;AACnB+C,QAAAA,UAAU,GAAG,IAAI,CAAA;QACjBT,MAAM,CAAC5C,KAAK,CAAC,GAAG,CAAC,CAAC7B,OAAO,CAAEO,KAAK,IAAK;UACjC,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,CAAEC,MAAM,IAAK;AACnC,MAAA,MAAMQ,WAAW,GAAGR,MAAM,CAACS,OAAO,CAACC,MAAM,CAAA;MACzC,IACI,IAAI,CAAC1B,cAAc,CAACwC,GAAG,CAAChB,WAAW,CAAC,IACnCA,WAAW,KAAK,GAAG,IAAI,IAAI,CAACxB,cAAc,CAACwC,GAAG,CAAC,GAAG,CAAE,EACvD;QACExB,MAAM,CAACe,SAAS,CAACG,GAAG,CAAC,IAAI,CAACvD,OAAO,CAACO,WAAW,CAAC,CAAA;AAClD,OAAC,MAAM;QACH8B,MAAM,CAACe,SAAS,CAACC,MAAM,CAAC,IAAI,CAACrD,OAAO,CAACO,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,CAACzB,MAAM,CAAA;AAC/B,IAAA,MAAMkI,OAAO,GAAG,IAAI,CAACjG,YAAY,CAACmC,IAAI,CAAA;IAEtC,IAAI,IAAI,CAACvC,OAAO,EAAE;MACd,IAAI,CAACA,OAAO,CAACa,WAAW,GAAG,CAAWwF,QAAAA,EAAAA,OAAO,CAAOD,IAAAA,EAAAA,KAAK,CAAE,CAAA,CAAA;AAC/D,KAAA;IAEA,OAAO;MAAEA,KAAK;AAAEC,MAAAA,OAAAA;KAAS,CAAA;AAC7B,GAAA;;AAEA;AACJ;AACA;AACA;AACA;EACIC,aAAaA,CAACC,IAAI,EAAE;AAChB,IAAA,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAACrC,QAAQ,CAACqC,IAAI,CAACC,WAAW,EAAE,CAAC,EAAE;MAC5C,IAAI,CAAC5H,OAAO,CAACU,UAAU,GAAGiH,IAAI,CAACC,WAAW,EAAE,CAAA;MAC5C,IAAI,CAAC7E,MAAM,EAAE,CAAA;AACjB,KAAA;AACJ,GAAA;;AAEA;AACJ;AACA;AACA;AACA;AACA;AACI8E,EAAAA,SAASA,CAACtD,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;AACI4E,EAAAA,YAAYA,CAACvD,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;EACI6E,sBAAsBA,CAACxD,IAAI,EAAE;AACzB,IAAA,OAAO,CAAC,GAAG,IAAI,CAAClD,cAAc,CAAC,CAC1B0B,MAAM,CAAEA,MAAM,IAAKA,MAAM,CAACiF,UAAU,CAAC,CAAGzD,EAAAA,IAAI,CAAG,CAAA,CAAA,CAAC,CAAC,CACjDW,GAAG,CAAEnC,MAAM,IAAKA,MAAM,CAACkB,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAC9C,GAAA;AACJ;;;;"}