@oscarpalmer/tabela 0.8.0 → 0.10.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.
Files changed (55) hide show
  1. package/dist/components/body.component.js +2 -15
  2. package/dist/components/footer.component.js +3 -3
  3. package/dist/components/header.component.js +2 -2
  4. package/dist/components/row.component.js +13 -4
  5. package/dist/helpers/dom.helpers.js +5 -10
  6. package/dist/helpers/misc.helpers.js +7 -0
  7. package/dist/helpers/style.helper.js +6 -0
  8. package/dist/managers/column.manager.js +7 -2
  9. package/dist/managers/data.manager.js +6 -4
  10. package/dist/managers/event.manager.js +6 -2
  11. package/dist/managers/filter.manager.js +92 -0
  12. package/dist/managers/{virtualization.manager.js → render.manager.js} +28 -22
  13. package/dist/managers/row.manager.js +9 -2
  14. package/dist/managers/selection.manager.js +191 -0
  15. package/dist/managers/sort.manager.js +17 -6
  16. package/dist/models/render.model.js +0 -0
  17. package/dist/tabela.full.js +1253 -105
  18. package/dist/tabela.js +19 -6
  19. package/package.json +1 -1
  20. package/src/components/body.component.ts +4 -21
  21. package/src/components/footer.component.ts +3 -3
  22. package/src/components/header.component.ts +2 -2
  23. package/src/components/row.component.ts +22 -7
  24. package/src/helpers/dom.helpers.ts +3 -10
  25. package/src/helpers/misc.helpers.ts +15 -0
  26. package/src/helpers/style.helper.ts +6 -0
  27. package/src/managers/column.manager.ts +9 -1
  28. package/src/managers/data.manager.ts +9 -5
  29. package/src/managers/event.manager.ts +10 -3
  30. package/src/managers/filter.manager.ts +154 -0
  31. package/src/managers/{virtualization.manager.ts → render.manager.ts} +36 -31
  32. package/src/managers/row.manager.ts +16 -2
  33. package/src/managers/selection.manager.ts +338 -0
  34. package/src/managers/sort.manager.ts +35 -16
  35. package/src/models/filter.model.ts +17 -0
  36. package/src/models/{virtualization.model.ts → render.model.ts} +3 -3
  37. package/src/models/sort.model.ts +1 -1
  38. package/src/models/tabela.model.ts +22 -2
  39. package/src/tabela.ts +28 -6
  40. package/types/components/row.component.d.ts +2 -2
  41. package/types/helpers/dom.helpers.d.ts +1 -1
  42. package/types/helpers/misc.helpers.d.ts +2 -0
  43. package/types/helpers/style.helper.d.ts +1 -0
  44. package/types/managers/data.manager.d.ts +1 -1
  45. package/types/managers/event.manager.d.ts +1 -1
  46. package/types/managers/filter.manager.d.ts +19 -0
  47. package/types/managers/{virtualization.manager.d.ts → render.manager.d.ts} +6 -6
  48. package/types/managers/selection.manager.d.ts +19 -0
  49. package/types/managers/sort.manager.d.ts +5 -2
  50. package/types/models/filter.model.d.ts +6 -0
  51. package/types/models/{virtualization.model.d.ts → render.model.d.ts} +3 -3
  52. package/types/models/sort.model.d.ts +1 -1
  53. package/types/models/tabela.model.d.ts +20 -2
  54. package/types/tabela.d.ts +3 -1
  55. /package/dist/models/{virtualization.model.js → filter.model.js} +0 -0
@@ -1,3 +1,14 @@
1
+ function compact$1(array, strict) {
2
+ if (!Array.isArray(array)) return [];
3
+ if (strict === true) return array.filter(Boolean);
4
+ const { length } = array;
5
+ const compacted = [];
6
+ for (let index = 0; index < length; index += 1) {
7
+ const item = array[index];
8
+ if (item != null) compacted.push(item);
9
+ }
10
+ return compacted;
11
+ }
1
12
  /**
2
13
  * Get the string value from any value
3
14
  * @param value Original value
@@ -12,6 +23,32 @@ function getString$1(value) {
12
23
  return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
13
24
  }
14
25
  /**
26
+ * Join an array of values into a string
27
+ * @param value Array of values
28
+ * @param delimiter Delimiter to use between values
29
+ * @returns Joined string
30
+ */
31
+ function join$1(value, delimiter) {
32
+ return compact$1(value).map(getString$1).join(typeof delimiter === "string" ? delimiter : "");
33
+ }
34
+ /**
35
+ * Split a string into words _(and other readable parts)_
36
+ * @param value Original string
37
+ * @returns Array of words found in the string
38
+ */
39
+ function words$1(value) {
40
+ return typeof value === "string" ? value.match(EXPRESSION_WORDS$1) ?? [] : [];
41
+ }
42
+ var EXPRESSION_WORDS$1 = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
43
+ /**
44
+ * Is the value a number?
45
+ * @param value Value to check
46
+ * @returns `true` if the value is a `number`, otherwise `false`
47
+ */
48
+ function isNumber$1(value) {
49
+ return typeof value === "number" && !Number.isNaN(value);
50
+ }
51
+ /**
15
52
  * Is the value a plain object?
16
53
  * @param value Value to check
17
54
  * @returns `true` if the value is a plain object, otherwise `false`
@@ -22,9 +59,237 @@ function isPlainObject$1(value) {
22
59
  const prototype = Object.getPrototypeOf(value);
23
60
  return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
24
61
  }
62
+ /**
63
+ * Clamp a number between a minimum and maximum value
64
+ * @param value Value to clamp
65
+ * @param minimum Minimum value
66
+ * @param maximum Maximum value
67
+ * @param loop If `true`, the value will loop around when smaller than the minimum or larger than the maximum _(defaults to `false`)_
68
+ * @returns Clamped value
69
+ */
70
+ function clamp$1(value, minimum, maximum, loop) {
71
+ if (![
72
+ value,
73
+ minimum,
74
+ maximum
75
+ ].every(isNumber$1)) return NaN;
76
+ if (value < minimum) return loop === true ? maximum : minimum;
77
+ return value > maximum ? loop === true ? minimum : maximum : value;
78
+ }
79
+ function getSizedMaximum$1(first, second) {
80
+ let actual;
81
+ if (typeof first === "number") actual = first;
82
+ else actual = typeof second === "number" ? second : MAXIMUM_DEFAULT$1;
83
+ return clamp$1(actual, 1, MAXIMUM_ABSOLUTE$1);
84
+ }
85
+ var MAXIMUM_ABSOLUTE$1 = 16777216;
86
+ var MAXIMUM_DEFAULT$1 = 1048576;
87
+ /**
88
+ * A Map with a maximum size
89
+ *
90
+ * Behavior is similar to a _LRU_-cache, where the least recently used entries are removed
91
+ */
92
+ var SizedMap$1 = class extends Map {
93
+ /**
94
+ * The maximum size of the Map
95
+ */
96
+ #maximumSize;
97
+ /**
98
+ * Is the Map full?
99
+ */
100
+ get full() {
101
+ return this.size >= this.#maximumSize;
102
+ }
103
+ get maximum() {
104
+ return this.#maximumSize;
105
+ }
106
+ constructor(first, second) {
107
+ const maximum = getSizedMaximum$1(first, second);
108
+ super();
109
+ this.#maximumSize = maximum;
110
+ if (Array.isArray(first)) {
111
+ const { length } = first;
112
+ if (length <= maximum) for (let index = 0; index < length; index += 1) this.set(...first[index]);
113
+ else for (let index = 0; index < maximum; index += 1) this.set(...first[length - maximum + index]);
114
+ }
115
+ }
116
+ /**
117
+ * @inheritdoc
118
+ */
119
+ get(key) {
120
+ const value = super.get(key);
121
+ if (value !== void 0 || this.has(key)) this.set(key, value);
122
+ return value;
123
+ }
124
+ /**
125
+ * @inheritdoc
126
+ */
127
+ set(key, value) {
128
+ if (this.has(key)) this.delete(key);
129
+ else if (this.size >= this.#maximumSize) this.delete(this.keys().next().value);
130
+ return super.set(key, value);
131
+ }
132
+ };
133
+ var Memoized$1 = class {
134
+ #state;
135
+ /**
136
+ * Maximum cache size
137
+ */
138
+ get maximum() {
139
+ return this.#state.cache?.maximum ?? NaN;
140
+ }
141
+ /**
142
+ * Current cache size
143
+ */
144
+ get size() {
145
+ return this.#state.cache?.size ?? NaN;
146
+ }
147
+ constructor(callback, options) {
148
+ const cache = new SizedMap$1(options.cacheSize);
149
+ const getter = (...parameters) => {
150
+ const key = options.cacheKey?.(...parameters) ?? (parameters.length === 1 ? parameters[0] : join$1(parameters.map(getString$1), "_"));
151
+ if (cache.has(key)) return cache.get(key);
152
+ const value = callback(...parameters);
153
+ cache.set(key, value);
154
+ return value;
155
+ };
156
+ this.#state = {
157
+ cache,
158
+ getter
159
+ };
160
+ }
161
+ /**
162
+ * Clear the cache
163
+ */
164
+ clear() {
165
+ this.#state.cache?.clear();
166
+ }
167
+ /**
168
+ * Delete a result from the cache
169
+ * @param key Key to delete
170
+ * @returns `true` if the key existed and was removed, otherwise `false`
171
+ */
172
+ delete(key) {
173
+ return this.#state.cache?.delete(key) ?? false;
174
+ }
175
+ /**
176
+ * Destroy the instance _(clearing its cache and removing its callback)_
177
+ */
178
+ destroy() {
179
+ this.#state.cache?.clear();
180
+ this.#state.cache = void 0;
181
+ this.#state.getter = void 0;
182
+ }
183
+ /**
184
+ * Get a result from the cache
185
+ * @param key Key to get
186
+ * @returns Cached result or `undefined` if it does not exist
187
+ */
188
+ get(key) {
189
+ return this.#state.cache?.get(key);
190
+ }
191
+ /**
192
+ * Does the result exist?
193
+ * @param key Key to check
194
+ * @returns `true` if the result exists, otherwise `false`
195
+ */
196
+ has(key) {
197
+ return this.#state.cache?.has(key) ?? false;
198
+ }
199
+ /**
200
+ * Run the callback with the provided parameters
201
+ * @param parameters Parameters to pass to the callback
202
+ * @returns Cached or computed _(then cached)_ result
203
+ */
204
+ run(...parameters) {
205
+ if (this.#state.cache == null || this.#state.getter == null) throw new Error("The Memoized instance has been destroyed");
206
+ return this.#state.getter(...parameters);
207
+ }
208
+ };
209
+ function getMemoizationOptions$1(input) {
210
+ const { cacheKey, cacheSize } = isPlainObject$1(input) ? input : {};
211
+ return {
212
+ cacheKey: typeof cacheKey === "function" ? cacheKey : void 0,
213
+ cacheSize: typeof cacheSize === "number" && cacheSize > 0 ? cacheSize : DEFAULT_CACHE_SIZE$1
214
+ };
215
+ }
216
+ /**
217
+ * Memoize a function, caching and retrieving results based on the first parameter
218
+ * @param callback Callback to memoize
219
+ * @param options Memoization options
220
+ * @returns Memoized instance
221
+ */
222
+ function memoize$1(callback, options) {
223
+ return new Memoized$1(callback, getMemoizationOptions$1(options));
224
+ }
225
+ var DEFAULT_CACHE_SIZE$1 = 1024;
226
+ /**
227
+ * Convert a string to camel case _(thisIsCamelCase)_
228
+ * @param value String to convert
229
+ * @returns Camel-cased string
230
+ */
231
+ function camelCase(value) {
232
+ return toCase("camel", value, true, false);
233
+ }
234
+ /**
235
+ * Capitalize the first letter of a string _(and lowercase the rest)_
236
+ * @param value String to capitalize
237
+ * @returns Capitalized string
238
+ */
239
+ function capitalize(value) {
240
+ if (typeof value !== "string" || value.length === 0) return "";
241
+ memoizedCapitalize ??= memoize$1((v) => v.length === 1 ? v.toLocaleUpperCase() : `${v.charAt(0).toLocaleUpperCase()}${v.slice(1).toLocaleLowerCase()}`);
242
+ return memoizedCapitalize.run(value);
243
+ }
244
+ function toCase(type, value, capitalizeAny, capitalizeFirst) {
245
+ caseMemoizers[type] ??= memoize$1(toCaseCallback.bind({
246
+ type,
247
+ capitalizeAny,
248
+ capitalizeFirst
249
+ }));
250
+ return caseMemoizers[type].run(value);
251
+ }
252
+ function toCaseCallback(value) {
253
+ if (typeof value !== "string") return "";
254
+ if (value.length < 1) return value;
255
+ const { capitalizeAny, capitalizeFirst, type } = this;
256
+ const parts = words$1(value);
257
+ const partsLength = parts.length;
258
+ const cased = [];
259
+ for (let partIndex = 0; partIndex < partsLength; partIndex += 1) {
260
+ const items = parts[partIndex].replace(EXPRESSION_ACRONYM, (full, one, two, three) => three === "s" ? full : `${one}-${two}${three}`).replace(EXPRESSION_CAMEL_CASE, REPLACEMENT_CAMEL_CASE).split("-");
261
+ const itemsLength = items.length;
262
+ const partResult = [];
263
+ let itemCount = 0;
264
+ for (let itemIndex = 0; itemIndex < itemsLength; itemIndex += 1) {
265
+ const item = items[itemIndex];
266
+ if (item.length === 0) continue;
267
+ if (!capitalizeAny || itemCount === 0 && partIndex === 0 && !capitalizeFirst) partResult.push(item.toLocaleLowerCase());
268
+ else partResult.push(capitalize(item));
269
+ itemCount += 1;
270
+ }
271
+ cased.push(join$1(partResult, delimiters[type]));
272
+ }
273
+ return join$1(cased, delimiters[type]);
274
+ }
275
+ var caseMemoizers = {};
276
+ var delimiters = {
277
+ camel: "",
278
+ kebab: "-",
279
+ pascal: "",
280
+ snake: "_"
281
+ };
282
+ var EXPRESSION_CAMEL_CASE = /(\p{Ll})(\p{Lu})/gu;
283
+ var EXPRESSION_ACRONYM = /(\p{Lu}*)(\p{Lu})(\p{Ll}+)/gu;
284
+ var REPLACEMENT_CAMEL_CASE = "$1-$2";
285
+ var memoizedCapitalize;
25
286
  function getBoolean(value, defaultValue) {
26
287
  return typeof value === "boolean" ? value : defaultValue ?? false;
27
288
  }
289
+ function getStyleValue(element, property, computed) {
290
+ const name = camelCase(property);
291
+ return computed ? getComputedStyle(element)[name] : element.style[name];
292
+ }
28
293
  /**
29
294
  * Is the value an event target?
30
295
  * @param value Value to check
@@ -57,6 +322,33 @@ function isNullableOrWhitespace(value) {
57
322
  return value == null || EXPRESSION_WHITESPACE$1.test(getString$1(value));
58
323
  }
59
324
  var EXPRESSION_WHITESPACE$1 = /^\s*$/;
325
+ function setElementValue(element, first, second, third, callback) {
326
+ if (!isHTMLOrSVGElement(element)) return;
327
+ if (typeof first === "string") setElementValues(element, first, second, third, callback);
328
+ else if (isAttribute(first)) setElementValues(element, first.name, first.value, third, callback);
329
+ }
330
+ function setElementValues(element, first, second, third, callback) {
331
+ if (!isHTMLOrSVGElement(element)) return;
332
+ if (typeof first === "string") {
333
+ callback(element, first, second, third);
334
+ return;
335
+ }
336
+ const isArray = Array.isArray(first);
337
+ if (!isArray && !(typeof first === "object" && first !== null)) return;
338
+ const entries = isArray ? first : Object.entries(first).map(([name, value]) => ({
339
+ name,
340
+ value
341
+ }));
342
+ const { length } = entries;
343
+ for (let index = 0; index < length; index += 1) {
344
+ const entry = entries[index];
345
+ if (typeof entry === "object" && typeof entry?.name === "string") callback(element, entry.name, entry.value, third);
346
+ }
347
+ }
348
+ function updateElementValue(element, key, value, set, remove, isBoolean, json) {
349
+ if (isBoolean ? value == null : isNullableOrWhitespace(value)) remove.call(element, key);
350
+ else set.call(element, key, json ? JSON.stringify(value) : String(value));
351
+ }
60
352
  function badAttributeHandler(name, value) {
61
353
  if (typeof name !== "string" || name.trim().length === 0 || typeof value !== "string") return true;
62
354
  if (EXPRESSION_CLOBBERED_NAME.test(name) && (value in document || value in formElement) || EXPRESSION_EVENT_NAME.test(name)) return true;
@@ -165,32 +457,28 @@ var elementEvents = {
165
457
  };
166
458
  var formElement = document.createElement("form");
167
459
  var textArea;
168
- function setElementValue(element, first, second, third, callback) {
169
- if (!isHTMLOrSVGElement(element)) return;
170
- if (typeof first === "string") setElementValues(element, first, second, third, callback);
171
- else if (isAttribute(first)) setElementValues(element, first.name, first.value, third, callback);
460
+ function setAttribute(element, first, second, third) {
461
+ setElementValue(element, first, second, third, updateAttribute);
172
462
  }
173
- function setElementValues(element, first, second, third, callback) {
174
- if (!isHTMLOrSVGElement(element)) return;
175
- if (typeof first === "string") {
176
- callback(element, first, second, third);
177
- return;
178
- }
179
- const isArray = Array.isArray(first);
180
- if (!isArray && !(typeof first === "object" && first !== null)) return;
181
- const entries = isArray ? first : Object.entries(first).map(([name, value]) => ({
182
- name,
183
- value
184
- }));
185
- const { length } = entries;
463
+ function setAttributes(element, attributes, dispatch) {
464
+ setElementValues(element, attributes, null, dispatch, updateAttribute);
465
+ }
466
+ /**
467
+ * Get styles from an element
468
+ * @param element Element to get the styles from
469
+ * @param properties Styles to get
470
+ * @param computed Get the computed styles? _(defaults to `false`)_
471
+ * @returns Style values
472
+ */
473
+ function getStyles(element, properties, computed) {
474
+ const styles = {};
475
+ if (!(isHTMLOrSVGElement(element) && Array.isArray(properties))) return styles;
476
+ const { length } = properties;
186
477
  for (let index = 0; index < length; index += 1) {
187
- const entry = entries[index];
188
- if (typeof entry === "object" && typeof entry?.name === "string") callback(element, entry.name, entry.value, third);
478
+ const property = properties[index];
479
+ if (typeof property === "string") styles[property] = getStyleValue(element, property, computed === true);
189
480
  }
190
- }
191
- function updateElementValue(element, key, value, set, remove, isBoolean, json) {
192
- if (isBoolean ? value == null : isNullableOrWhitespace(value)) remove.call(element, key);
193
- else set.call(element, key, json ? JSON.stringify(value) : String(value));
481
+ return styles;
194
482
  }
195
483
  /**
196
484
  * Set styles on an element
@@ -200,6 +488,38 @@ function updateElementValue(element, key, value, set, remove, isBoolean, json) {
200
488
  function setStyles(element, styles) {
201
489
  setElementValues(element, styles, null, null, updateStyleProperty);
202
490
  }
491
+ /**
492
+ * Toggle styles for an element
493
+ * @param element Element to style
494
+ * @param styles Styles to be set or removed
495
+ * @returns Style toggler
496
+ */
497
+ function toggleStyles(element, styles) {
498
+ function toggle(set) {
499
+ hasSet = set;
500
+ let next;
501
+ if (set) {
502
+ values = getStyles(element, keys);
503
+ next = styles;
504
+ } else {
505
+ next = { ...values };
506
+ values = {};
507
+ for (const key of keys) values[key] = void 0;
508
+ }
509
+ setStyles(element, next);
510
+ }
511
+ const keys = Object.keys(styles);
512
+ let hasSet = false;
513
+ let values = {};
514
+ return {
515
+ set() {
516
+ if (!hasSet) toggle(true);
517
+ },
518
+ remove() {
519
+ if (hasSet) toggle(false);
520
+ }
521
+ };
522
+ }
203
523
  function updateStyleProperty(element, key, value) {
204
524
  updateElementValue(element, key, value, function(property, style) {
205
525
  this.style[property] = style;
@@ -207,18 +527,12 @@ function updateStyleProperty(element, key, value) {
207
527
  this.style[property] = "";
208
528
  }, false, false);
209
529
  }
210
- function setAttribute(element, first, second, third) {
211
- setElementValue(element, first, second, third, updateAttribute);
212
- }
213
- function setAttributes(element, attributes, dispatch) {
214
- setElementValues(element, attributes, null, dispatch, updateAttribute);
215
- }
216
530
  function createCell(width, body) {
217
531
  const cell = createElement("div", {
218
532
  className: "tabela__cell",
219
533
  role: "cell"
220
534
  }, {}, { width: `${width}px` });
221
- if (body ?? true) cell.classList.add("tabela__cell-body");
535
+ if (body ?? true) cell.classList.add("tabela__cell--body");
222
536
  return cell;
223
537
  }
224
538
  function createElement(tagName, properties, attributes, style) {
@@ -235,33 +549,21 @@ function createRowGroup(withRow) {
235
549
  role: "rowgroup"
236
550
  }, {}, {});
237
551
  if (!(withRow ?? true)) return group;
238
- const row = createRow(false);
552
+ const row = createRow();
239
553
  group.append(row);
240
554
  return {
241
555
  group,
242
556
  row
243
557
  };
244
558
  }
245
- function createRow(withStyle) {
246
- const row = createElement("div", {
559
+ function createRow() {
560
+ return createElement("div", {
247
561
  className: "tabela__row",
248
562
  role: "row"
249
563
  }, {}, {});
250
- if (withStyle ?? true) setStyles(row, {
251
- inset: "0 auto auto 0",
252
- position: "absolute"
253
- });
254
- return row;
255
564
  }
256
565
  function createFaker() {
257
- return createElement("div", {}, {}, {
258
- height: "0",
259
- inset: "0 auto auto 0",
260
- opacity: "0",
261
- pointerEvents: "none",
262
- position: "absolute",
263
- width: "1px"
264
- });
566
+ return createElement("div", { className: "tabela__faker" }, {}, {});
265
567
  }
266
568
  var BodyComponent = class {
267
569
  elements = {
@@ -271,13 +573,8 @@ var BodyComponent = class {
271
573
  constructor() {
272
574
  const group = createRowGroup(false);
273
575
  this.elements.group = group;
274
- group.className += " tabela__rowgroup-body";
576
+ group.className += " tabela__rowgroup--body";
275
577
  group.tabIndex = 0;
276
- setStyles(group, {
277
- height: "100%",
278
- overflow: "auto",
279
- position: "relative"
280
- });
281
578
  group.append(this.elements.faker);
282
579
  }
283
580
  destroy() {
@@ -294,8 +591,8 @@ var FooterComponent = class {
294
591
  row,
295
592
  cells: []
296
593
  };
297
- group.className += " tabela__rowgroup-footer";
298
- row.className += " tabela__row-footer";
594
+ group.className += " tabela__rowgroup--footer";
595
+ row.className += " tabela__row--footer";
299
596
  }
300
597
  destroy() {
301
598
  this.elements.cells.length = 0;
@@ -309,7 +606,7 @@ var FooterComponent = class {
309
606
  elements.row.innerHTML = "";
310
607
  for (let index = 0; index < length; index += 1) {
311
608
  const cell = createCell(columns[index].options.width ?? 4, false);
312
- cell.className += " tabela__cell-footer";
609
+ cell.className += " tabela__cell--footer";
313
610
  cell.innerHTML = "&nbsp;";
314
611
  elements.cells.push(cell);
315
612
  elements.row.append(cell);
@@ -324,8 +621,8 @@ var HeaderComponent = class {
324
621
  group,
325
622
  row
326
623
  };
327
- group.className += " tabela__rowgroup-header";
328
- row.className += " tabela__row-header";
624
+ group.className += " tabela__rowgroup--header";
625
+ row.className += " tabela__row--header";
329
626
  }
330
627
  destroy() {
331
628
  this.elements.group = void 0;
@@ -383,6 +680,8 @@ var ColumnManager = class {
383
680
  this.set(columns);
384
681
  }
385
682
  destroy() {
683
+ const { length } = this.items;
684
+ for (let index = 0; index < length; index += 1) this.items[index].destroy();
386
685
  this.items.length = 0;
387
686
  }
388
687
  remove(value) {
@@ -392,11 +691,14 @@ var ColumnManager = class {
392
691
  if (length === 0) return;
393
692
  for (let fieldIndex = 0; fieldIndex < length; fieldIndex += 1) {
394
693
  const itemIndex = items.findIndex((component) => component.options.field === fields[fieldIndex]);
395
- if (itemIndex > -1) items.splice(itemIndex, 1);
694
+ if (itemIndex > -1) {
695
+ items[itemIndex].destroy();
696
+ items.splice(itemIndex, 1);
697
+ }
396
698
  }
397
699
  components.header.update(items);
398
700
  components.footer.update(items);
399
- managers.virtualization.removeCells(fields);
701
+ managers.render.removeCells(fields);
400
702
  }
401
703
  set(columns) {
402
704
  const { components, items } = this;
@@ -480,6 +782,14 @@ function isConstructor(value) {
480
782
  return typeof value === "function" && value.prototype?.constructor === value;
481
783
  }
482
784
  /**
785
+ * Is the value a key?
786
+ * @param value Value to check
787
+ * @returns `true` if the value is a `Key` _(`number` or `string`)_, otherwise `false`
788
+ */
789
+ function isKey(value) {
790
+ return typeof value === "number" || typeof value === "string";
791
+ }
792
+ /**
483
793
  * Is the value a number?
484
794
  * @param value Value to check
485
795
  * @returns `true` if the value is a `number`, otherwise `false`
@@ -498,6 +808,90 @@ function isPlainObject(value) {
498
808
  const prototype = Object.getPrototypeOf(value);
499
809
  return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
500
810
  }
811
+ /**
812
+ * Is the value a typed array?
813
+ * @param value Value to check
814
+ * @returns `true` if the value is a typed array, otherwise `false`
815
+ */
816
+ function isTypedArray(value) {
817
+ TYPED_ARRAYS ??= new Set([
818
+ Int8Array,
819
+ Uint8Array,
820
+ Uint8ClampedArray,
821
+ Int16Array,
822
+ Uint16Array,
823
+ Int32Array,
824
+ Uint32Array,
825
+ Float32Array,
826
+ Float64Array,
827
+ BigInt64Array,
828
+ BigUint64Array
829
+ ]);
830
+ return TYPED_ARRAYS.has(value?.constructor);
831
+ }
832
+ var TYPED_ARRAYS;
833
+ /**
834
+ * Chunk an array into smaller arrays
835
+ * @param array Array to chunk
836
+ * @param size Size of each chunk _(minimum is `1`, maximum is `5000`; defaults to `5000`)_
837
+ * @returns Array of arrays
838
+ */
839
+ function chunk(array, size) {
840
+ if (!Array.isArray(array)) return [];
841
+ if (array.length === 0) return [];
842
+ const { length } = array;
843
+ const actualSize = typeof size === "number" && size > 0 && size <= MAX_SIZE ? size : MAX_SIZE;
844
+ if (length <= actualSize) return [array];
845
+ const chunks = [];
846
+ let index = 0;
847
+ while (index < length) {
848
+ chunks.push(array.slice(index, index + actualSize));
849
+ index += actualSize;
850
+ }
851
+ return chunks;
852
+ }
853
+ var MAX_SIZE = 5e3;
854
+ function compact(array, strict) {
855
+ if (!Array.isArray(array)) return [];
856
+ if (strict === true) return array.filter(Boolean);
857
+ const { length } = array;
858
+ const compacted = [];
859
+ for (let index = 0; index < length; index += 1) {
860
+ const item = array[index];
861
+ if (item != null) compacted.push(item);
862
+ }
863
+ return compacted;
864
+ }
865
+ function insertChunkedValues(type, array, items, start, deleteCount) {
866
+ const actualDeleteCount = deleteCount < 0 ? 0 : deleteCount;
867
+ const actualStart = Math.min(Math.max(0, start), array.length);
868
+ const chunked = chunk(items);
869
+ const lastIndex = chunked.length - 1;
870
+ let index = Number(chunked.length);
871
+ let returned;
872
+ while (index > 0) {
873
+ index -= 1;
874
+ const spliced = array.splice(actualStart, index === lastIndex ? actualDeleteCount : 0, ...chunked[index]);
875
+ if (returned == null) returned = spliced;
876
+ else returned.push(...spliced);
877
+ }
878
+ if (type === "insert") return array;
879
+ return type === "splice" ? returned : array.length;
880
+ }
881
+ function insertValues(type, array, items, start, deleteCount) {
882
+ const spliceArray = type === "insert" || type === "splice";
883
+ if (!Array.isArray(array) || typeof start !== "number" || !Array.isArray(items) || items.length === 0) return spliceArray ? [] : 0;
884
+ return insertChunkedValues(type, array, items, start, spliceArray ? deleteCount : 0);
885
+ }
886
+ /**
887
+ * Push items into an array _(at the end)_
888
+ * @param array Original array
889
+ * @param pushed Pushed items
890
+ * @returns New length of the array
891
+ */
892
+ function push(array, pushed) {
893
+ return insertValues("push", array, pushed, array.length, 0);
894
+ }
501
895
  function aggregate(type, array, key) {
502
896
  const length = Array.isArray(array) ? array.length : 0;
503
897
  if (length === 0) return {
@@ -556,6 +950,15 @@ function getString(value) {
556
950
  return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
557
951
  }
558
952
  /**
953
+ * Join an array of values into a string
954
+ * @param value Array of values
955
+ * @param delimiter Delimiter to use between values
956
+ * @returns Joined string
957
+ */
958
+ function join(value, delimiter) {
959
+ return compact(value).map(getString).join(typeof delimiter === "string" ? delimiter : "");
960
+ }
961
+ /**
559
962
  * Split a string into words _(and other readable parts)_
560
963
  * @param value Original string
561
964
  * @returns Array of words found in the string
@@ -659,7 +1062,7 @@ function compareSymbols(first, second) {
659
1062
  }
660
1063
  function compareValue(first, second, compareStrings) {
661
1064
  const firstType = typeof first;
662
- if (firstType === typeof second && firstType in comparators) return comparators[firstType](first, second);
1065
+ if (firstType === typeof second && firstType in comparators$1) return comparators$1[firstType](first, second);
663
1066
  if (first instanceof Date && second instanceof Date) return compareNumbers(first.getTime(), second.getTime());
664
1067
  return compare.handlers.handle(first, second, compareStrings);
665
1068
  }
@@ -667,7 +1070,7 @@ function getComparisonParts(value) {
667
1070
  if (Array.isArray(value)) return value;
668
1071
  return typeof value === "object" ? [value] : words(getString(value));
669
1072
  }
670
- var comparators = {
1073
+ var comparators$1 = {
671
1074
  bigint: compareNumbers,
672
1075
  boolean: compareNumbers,
673
1076
  number: compareNumbers,
@@ -678,7 +1081,7 @@ function getCallback(value, key, forObject) {
678
1081
  if (forObject && typeof value.value === "function") return value.value;
679
1082
  return typeof value === "function" ? value : void 0;
680
1083
  }
681
- function getKey(value, forObject) {
1084
+ function getKey$1(value, forObject) {
682
1085
  if (forObject && typeof value.key === "string") return value.key;
683
1086
  return typeof value === "string" ? value : void 0;
684
1087
  }
@@ -694,7 +1097,7 @@ function getSorter(value, modifier) {
694
1097
  modifier
695
1098
  };
696
1099
  sorter.compare = forObject && typeof value.compare === "function" ? value.compare : void 0;
697
- sorter.key = getKey(value, forObject);
1100
+ sorter.key = getKey$1(value, forObject);
698
1101
  sorter.modifier = getModifier(value, modifier, forObject);
699
1102
  sorter.callback = getCallback(value, sorter.key, forObject);
700
1103
  if (sorter.key != null || sorter.callback != null) {
@@ -780,7 +1183,7 @@ var DataManager = class {
780
1183
  }
781
1184
  async add(data, render) {
782
1185
  const { field, values } = this;
783
- values.objects.array.push(...data);
1186
+ push(values.objects.array, data);
784
1187
  values.objects.mapped = toMap(values.objects.array, field);
785
1188
  if (render) this.render();
786
1189
  }
@@ -793,6 +1196,7 @@ var DataManager = class {
793
1196
  values.keys.active = void 0;
794
1197
  values.keys.original.length = 0;
795
1198
  values.objects.array.length = 0;
1199
+ this.handlers = void 0;
796
1200
  }
797
1201
  get(active) {
798
1202
  const { values } = this;
@@ -816,8 +1220,9 @@ var DataManager = class {
816
1220
  render() {
817
1221
  const { field, managers, values } = this;
818
1222
  values.keys.original = sort(values.objects.array.map((item) => item[field]));
819
- if (managers.sort.items.length > 0) managers.sort.sort();
820
- else managers.virtualization.update(true);
1223
+ if (Object.keys(managers.filter.items).length > 0) managers.filter.filter();
1224
+ else if (managers.sort.items.length > 0) managers.sort.sort();
1225
+ else managers.render.update(true);
821
1226
  }
822
1227
  set(data) {
823
1228
  const { field, values } = this;
@@ -957,6 +1362,26 @@ function createEventOptions(options) {
957
1362
  signal: options?.signal instanceof AbortSignal ? options.signal : void 0
958
1363
  };
959
1364
  }
1365
+ /**
1366
+ * Get the X- and Y-coordinates from a pointer event
1367
+ * @param event Pointer event
1368
+ * @returns X- and Y-coordinates
1369
+ */
1370
+ function getPosition(event) {
1371
+ let x;
1372
+ let y;
1373
+ if (event instanceof MouseEvent) {
1374
+ x = event.clientX;
1375
+ y = event.clientY;
1376
+ } else if (event instanceof TouchEvent) {
1377
+ x = event.touches[0]?.clientX;
1378
+ y = event.touches[0]?.clientY;
1379
+ }
1380
+ return typeof x === "number" && typeof y === "number" ? {
1381
+ x,
1382
+ y
1383
+ } : void 0;
1384
+ }
960
1385
  function on(target, type, listener, options) {
961
1386
  if (!isEventTarget(target) || typeof type !== "string" || typeof listener !== "function") return noop;
962
1387
  const extended = createEventOptions(options);
@@ -1156,9 +1581,9 @@ function getSupport() {
1156
1581
  })();
1157
1582
  var EventManager = class {
1158
1583
  listener;
1159
- constructor(managers, element) {
1584
+ constructor(element, managers) {
1160
1585
  this.managers = managers;
1161
- on(element, "click", (event) => {
1586
+ this.listener = on(element, "click", (event) => {
1162
1587
  this.onClick(event);
1163
1588
  }, { passive: false });
1164
1589
  }
@@ -1172,6 +1597,10 @@ var EventManager = class {
1172
1597
  case "heading":
1173
1598
  this.onSort(event, target);
1174
1599
  break;
1600
+ case "row":
1601
+ this.managers.selection.handle(event, target);
1602
+ break;
1603
+ default: break;
1175
1604
  }
1176
1605
  }
1177
1606
  onSort(event, target) {
@@ -1181,6 +1610,489 @@ var EventManager = class {
1181
1610
  if (field != null) managers.sort.toggle(event, field, direction);
1182
1611
  }
1183
1612
  };
1613
+ /**
1614
+ * Clamp a number between a minimum and maximum value
1615
+ * @param value Value to clamp
1616
+ * @param minimum Minimum value
1617
+ * @param maximum Maximum value
1618
+ * @param loop If `true`, the value will loop around when smaller than the minimum or larger than the maximum _(defaults to `false`)_
1619
+ * @returns Clamped value
1620
+ */
1621
+ function clamp(value, minimum, maximum, loop) {
1622
+ if (![
1623
+ value,
1624
+ minimum,
1625
+ maximum
1626
+ ].every(isNumber)) return NaN;
1627
+ if (value < minimum) return loop === true ? maximum : minimum;
1628
+ return value > maximum ? loop === true ? minimum : maximum : value;
1629
+ }
1630
+ /**
1631
+ * Get the number value from an unknown value _(based on Lodash)_
1632
+ * @param value Original value
1633
+ * @returns Original value as a number, or `NaN` if the value is unable to be parsed
1634
+ */
1635
+ function getNumber(value) {
1636
+ if (typeof value === "number") return value;
1637
+ if (typeof value === "bigint" || typeof value === "boolean") return Number(value);
1638
+ if (value == null || typeof value === "symbol") return NaN;
1639
+ if (typeof value === "function") return getNumber(value());
1640
+ let parsed = value.valueOf();
1641
+ if (typeof parsed === "object") parsed = parsed.toString();
1642
+ if (typeof parsed !== "string") return getNumber(parsed);
1643
+ const trimmed = parsed.trim();
1644
+ if (trimmed.length === 0) return NaN;
1645
+ if (EXPRESSION_ZEROISH.test(parsed)) return 0;
1646
+ const isBinary = EXPRESSION_BINARY.test(trimmed);
1647
+ if (isBinary || EXPRESSION_OCTAL.test(trimmed)) return Number.parseInt(trimmed.slice(2), isBinary ? 2 : OCTAL_VALUE);
1648
+ return Number(EXPRESSION_HEX.test(trimmed) ? trimmed : trimmed.replace(EXPRESSION_UNDERSCORE, ""));
1649
+ }
1650
+ var EXPRESSION_BINARY = /^0b[01]+$/i;
1651
+ var EXPRESSION_HEX = /^0x[0-9a-f]+$/i;
1652
+ var EXPRESSION_OCTAL = /^0o[0-7]+$/i;
1653
+ var EXPRESSION_UNDERSCORE = /_/g;
1654
+ var EXPRESSION_ZEROISH = /^\s*0+\s*$/;
1655
+ var OCTAL_VALUE = 8;
1656
+ function getSizedMaximum(first, second) {
1657
+ let actual;
1658
+ if (typeof first === "number") actual = first;
1659
+ else actual = typeof second === "number" ? second : MAXIMUM_DEFAULT;
1660
+ return clamp(actual, 1, MAXIMUM_ABSOLUTE);
1661
+ }
1662
+ var MAXIMUM_ABSOLUTE = 16777216;
1663
+ var MAXIMUM_DEFAULT = 1048576;
1664
+ /**
1665
+ * A Map with a maximum size
1666
+ *
1667
+ * Behavior is similar to a _LRU_-cache, where the least recently used entries are removed
1668
+ */
1669
+ var SizedMap = class extends Map {
1670
+ /**
1671
+ * The maximum size of the Map
1672
+ */
1673
+ #maximumSize;
1674
+ /**
1675
+ * Is the Map full?
1676
+ */
1677
+ get full() {
1678
+ return this.size >= this.#maximumSize;
1679
+ }
1680
+ get maximum() {
1681
+ return this.#maximumSize;
1682
+ }
1683
+ constructor(first, second) {
1684
+ const maximum = getSizedMaximum(first, second);
1685
+ super();
1686
+ this.#maximumSize = maximum;
1687
+ if (Array.isArray(first)) {
1688
+ const { length } = first;
1689
+ if (length <= maximum) for (let index = 0; index < length; index += 1) this.set(...first[index]);
1690
+ else for (let index = 0; index < maximum; index += 1) this.set(...first[length - maximum + index]);
1691
+ }
1692
+ }
1693
+ /**
1694
+ * @inheritdoc
1695
+ */
1696
+ get(key) {
1697
+ const value = super.get(key);
1698
+ if (value !== void 0 || this.has(key)) this.set(key, value);
1699
+ return value;
1700
+ }
1701
+ /**
1702
+ * @inheritdoc
1703
+ */
1704
+ set(key, value) {
1705
+ if (this.has(key)) this.delete(key);
1706
+ else if (this.size >= this.#maximumSize) this.delete(this.keys().next().value);
1707
+ return super.set(key, value);
1708
+ }
1709
+ };
1710
+ var Memoized = class {
1711
+ #state;
1712
+ /**
1713
+ * Maximum cache size
1714
+ */
1715
+ get maximum() {
1716
+ return this.#state.cache?.maximum ?? NaN;
1717
+ }
1718
+ /**
1719
+ * Current cache size
1720
+ */
1721
+ get size() {
1722
+ return this.#state.cache?.size ?? NaN;
1723
+ }
1724
+ constructor(callback, options) {
1725
+ const cache = new SizedMap(options.cacheSize);
1726
+ const getter = (...parameters) => {
1727
+ const key = options.cacheKey?.(...parameters) ?? (parameters.length === 1 ? parameters[0] : join(parameters.map(getString), "_"));
1728
+ if (cache.has(key)) return cache.get(key);
1729
+ const value = callback(...parameters);
1730
+ cache.set(key, value);
1731
+ return value;
1732
+ };
1733
+ this.#state = {
1734
+ cache,
1735
+ getter
1736
+ };
1737
+ }
1738
+ /**
1739
+ * Clear the cache
1740
+ */
1741
+ clear() {
1742
+ this.#state.cache?.clear();
1743
+ }
1744
+ /**
1745
+ * Delete a result from the cache
1746
+ * @param key Key to delete
1747
+ * @returns `true` if the key existed and was removed, otherwise `false`
1748
+ */
1749
+ delete(key) {
1750
+ return this.#state.cache?.delete(key) ?? false;
1751
+ }
1752
+ /**
1753
+ * Destroy the instance _(clearing its cache and removing its callback)_
1754
+ */
1755
+ destroy() {
1756
+ this.#state.cache?.clear();
1757
+ this.#state.cache = void 0;
1758
+ this.#state.getter = void 0;
1759
+ }
1760
+ /**
1761
+ * Get a result from the cache
1762
+ * @param key Key to get
1763
+ * @returns Cached result or `undefined` if it does not exist
1764
+ */
1765
+ get(key) {
1766
+ return this.#state.cache?.get(key);
1767
+ }
1768
+ /**
1769
+ * Does the result exist?
1770
+ * @param key Key to check
1771
+ * @returns `true` if the result exists, otherwise `false`
1772
+ */
1773
+ has(key) {
1774
+ return this.#state.cache?.has(key) ?? false;
1775
+ }
1776
+ /**
1777
+ * Run the callback with the provided parameters
1778
+ * @param parameters Parameters to pass to the callback
1779
+ * @returns Cached or computed _(then cached)_ result
1780
+ */
1781
+ run(...parameters) {
1782
+ if (this.#state.cache == null || this.#state.getter == null) throw new Error("The Memoized instance has been destroyed");
1783
+ return this.#state.getter(...parameters);
1784
+ }
1785
+ };
1786
+ function getMemoizationOptions(input) {
1787
+ const { cacheKey, cacheSize } = isPlainObject(input) ? input : {};
1788
+ return {
1789
+ cacheKey: typeof cacheKey === "function" ? cacheKey : void 0,
1790
+ cacheSize: typeof cacheSize === "number" && cacheSize > 0 ? cacheSize : DEFAULT_CACHE_SIZE
1791
+ };
1792
+ }
1793
+ /**
1794
+ * Memoize a function, caching and retrieving results based on the first parameter
1795
+ * @param callback Callback to memoize
1796
+ * @param options Memoization options
1797
+ * @returns Memoized instance
1798
+ */
1799
+ function memoize(callback, options) {
1800
+ return new Memoized(callback, getMemoizationOptions(options));
1801
+ }
1802
+ var DEFAULT_CACHE_SIZE = 1024;
1803
+ /**
1804
+ * Check if a string ends with a specified substring
1805
+ * @param haystack String to look in
1806
+ * @param needle String to look for
1807
+ * @param ignoreCase Ignore case when matching? _(defaults to `false`)_
1808
+ * @returns `true` if the string ends with the given substring, otherwise `false`
1809
+ */
1810
+ function endsWith(haystack, needle, ignoreCase) {
1811
+ return match("endsWith", haystack, needle, ignoreCase === true);
1812
+ }
1813
+ /**
1814
+ * Check if a string includes a specified substring
1815
+ * @param haystack String to look in
1816
+ * @param needle String to look for
1817
+ * @param ignoreCase Ignore case when matching? _(defaults to `false`)_
1818
+ * @returns `true` if the string includes the given substring, otherwise `false`
1819
+ */
1820
+ function includes(haystack, needle, ignoreCase) {
1821
+ return match("includes", haystack, needle, ignoreCase === true);
1822
+ }
1823
+ function match(type, haystack, needle, ignoreCase) {
1824
+ if (typeof haystack !== "string" || typeof needle !== "string") return false;
1825
+ matchMemoizers[type] ??= memoize(matchCallback.bind(type));
1826
+ return matchMemoizers[type].run(haystack, needle, ignoreCase);
1827
+ }
1828
+ function matchCallback(haystack, needle, ignoreCase) {
1829
+ return (ignoreCase ? haystack.toLocaleLowerCase() : haystack)[this](ignoreCase ? needle.toLocaleLowerCase() : needle);
1830
+ }
1831
+ /**
1832
+ * Check if a string starts with a specified substring
1833
+ * @param haystack String to look in
1834
+ * @param needle String to look for
1835
+ * @param ignoreCase Ignore case when matching? _(defaults to `false`)_
1836
+ * @returns `true` if the string starts with the given substring, otherwise `false`
1837
+ */
1838
+ function startsWith(haystack, needle, ignoreCase) {
1839
+ return match("startsWith", haystack, needle, ignoreCase === true);
1840
+ }
1841
+ var matchMemoizers = {};
1842
+ function equal(first, second, options) {
1843
+ return equalValue(first, second, getEqualOptions(options));
1844
+ }
1845
+ equal.handlers = getCompareHandlers(equal, { callback: Object.is });
1846
+ equal.initialize = initializeEqualizer;
1847
+ equal.register = registerEqualizer;
1848
+ equal.unregister = unregisterEqualizer;
1849
+ function equalArray(first, second, options) {
1850
+ const { length } = first;
1851
+ if (length !== second.length) return false;
1852
+ let offset = 0;
1853
+ if (length >= ARRAY_THRESHOLD) {
1854
+ offset = Math.round(length / ARRAY_PEEK_PERCENTAGE);
1855
+ offset = offset > ARRAY_THRESHOLD ? ARRAY_THRESHOLD : offset;
1856
+ for (let index = 0; index < offset; index += 1) if (!(equalValue(first[index], second[index], options) && equalValue(first[length - index - 1], second[length - index - 1], options))) return false;
1857
+ }
1858
+ const firstChunks = chunk(first.slice(offset, length - offset), ARRAY_THRESHOLD);
1859
+ const secondChunks = chunk(second.slice(offset, length - offset), ARRAY_THRESHOLD);
1860
+ const chunksLength = firstChunks.length;
1861
+ for (let chunkIndex = 0; chunkIndex < chunksLength; chunkIndex += 1) {
1862
+ const firstChunk = firstChunks[chunkIndex];
1863
+ const secondChunk = secondChunks[chunkIndex];
1864
+ const chunkLength = firstChunk.length;
1865
+ for (let index = 0; index < chunkLength; index += 1) if (!equalValue(firstChunk[index], secondChunk[index], options)) return false;
1866
+ }
1867
+ return true;
1868
+ }
1869
+ function equalArrayBuffer(first, second, options) {
1870
+ return first.byteLength === second.byteLength ? equalArray(new Uint8Array(first), new Uint8Array(second), options) : false;
1871
+ }
1872
+ function equalDataView(first, second, options) {
1873
+ return first.byteOffset === second.byteOffset ? equalArrayBuffer(first.buffer, second.buffer, options) : false;
1874
+ }
1875
+ function equalMap(first, second, options) {
1876
+ const { size } = first;
1877
+ if (size !== second.size) return false;
1878
+ const firstKeys = [...first.keys()];
1879
+ const secondKeys = [...second.keys()];
1880
+ if (firstKeys.some((key) => !secondKeys.includes(key))) return false;
1881
+ for (let index = 0; index < size; index += 1) {
1882
+ const key = firstKeys[index];
1883
+ if (!equalValue(first.get(key), second.get(key), options)) return false;
1884
+ }
1885
+ return true;
1886
+ }
1887
+ function equalPlainObject(first, second, options) {
1888
+ let firstKeys = [...Object.keys(first), ...Object.getOwnPropertySymbols(first)];
1889
+ let secondKeys = [...Object.keys(second), ...Object.getOwnPropertySymbols(second)];
1890
+ if (options.ignoreKeys.enabled || options.ignoreExpressions.enabled) {
1891
+ firstKeys = firstKeys.filter((key) => filterKey(key, options));
1892
+ secondKeys = secondKeys.filter((key) => filterKey(key, options));
1893
+ }
1894
+ const { length } = firstKeys;
1895
+ if (length !== secondKeys.length || firstKeys.some((key) => !secondKeys.includes(key))) return false;
1896
+ for (let index = 0; index < length; index += 1) {
1897
+ const key = firstKeys[index];
1898
+ if (!equalValue(first[key], second[key], options)) return false;
1899
+ }
1900
+ return true;
1901
+ }
1902
+ function equalProperties(first, second, properties, options) {
1903
+ const { length } = properties;
1904
+ for (let index = 0; index < length; index += 1) {
1905
+ const property = properties[index];
1906
+ if (!equalValue(first[property], second[property], options)) return false;
1907
+ }
1908
+ return true;
1909
+ }
1910
+ function equalSet(first, second, options) {
1911
+ const { size } = first;
1912
+ if (size !== second.size) return false;
1913
+ const firstValues = [...first];
1914
+ const secondValues = [...second];
1915
+ for (let index = 0; index < size; index += 1) {
1916
+ const firstValue = firstValues[index];
1917
+ if (!secondValues.some((secondValue) => equalValue(firstValue, secondValue, options))) return false;
1918
+ }
1919
+ return true;
1920
+ }
1921
+ function equalTypedArray(first, second) {
1922
+ if (first.constructor !== second.constructor) return false;
1923
+ if (first.byteLength !== second.byteLength) return false;
1924
+ const { length } = first;
1925
+ for (let index = 0; index < length; index += 1) if (first[index] !== second[index]) return false;
1926
+ return true;
1927
+ }
1928
+ function equalValue(first, second, options) {
1929
+ if (options.relaxedNullish && first == null && second == null) return true;
1930
+ switch (true) {
1931
+ case Object.is(first, second): return true;
1932
+ case first == null || second == null: return first === second;
1933
+ case typeof first !== typeof second: return false;
1934
+ case typeof first === "string" && options.ignoreCase === true: return Object.is(first.toLocaleLowerCase(), second.toLocaleLowerCase());
1935
+ case first instanceof ArrayBuffer && second instanceof ArrayBuffer: return equalArrayBuffer(first, second, options);
1936
+ case first instanceof Date && second instanceof Date: return Object.is(Number(first), Number(second));
1937
+ case first instanceof DataView && second instanceof DataView: return equalDataView(first, second, options);
1938
+ case first instanceof Error && second instanceof Error: return equalProperties(first, second, ["name", "message"], options);
1939
+ case first instanceof Map && second instanceof Map: return equalMap(first, second, options);
1940
+ case first instanceof RegExp && second instanceof RegExp: return equalProperties(first, second, ["source", "flags"], options);
1941
+ case first instanceof Set && second instanceof Set: return equalSet(first, second, options);
1942
+ case Array.isArray(first) && Array.isArray(second): return equalArray(first, second, options);
1943
+ case isPlainObject(first) && isPlainObject(second): return equalPlainObject(first, second, options);
1944
+ case isTypedArray(first) && isTypedArray(second): return equalTypedArray(first, second);
1945
+ default: return equal.handlers.handle(first, second, options);
1946
+ }
1947
+ }
1948
+ /**
1949
+ * Create an equalizer with predefined options
1950
+ * @param options Comparison options
1951
+ * @returns Equalizer function
1952
+ */
1953
+ function initializeEqualizer(options) {
1954
+ const actual = getEqualOptions(options);
1955
+ const equalizer = (first, second) => equalValue(first, second, actual);
1956
+ equalizer.register = registerEqualizer;
1957
+ equalizer.unregister = unregisterEqualizer;
1958
+ return equalizer;
1959
+ }
1960
+ /**
1961
+ * Register a equality comparison function for a specific class
1962
+ * @param constructor Class constructor
1963
+ * @param fn Comparison function
1964
+ */
1965
+ function registerEqualizer(constructor, handler) {
1966
+ equal.handlers.register(constructor, handler);
1967
+ }
1968
+ /**
1969
+ * Unregister a equality comparison handler for a specific class
1970
+ * @param constructor Class constructor
1971
+ */
1972
+ function unregisterEqualizer(constructor) {
1973
+ equal.handlers.unregister(constructor);
1974
+ }
1975
+ function filterKey(key, options) {
1976
+ if (typeof key !== "string") return true;
1977
+ if (options.ignoreExpressions.enabled && options.ignoreExpressions.values.some((expression) => expression.test(key))) return false;
1978
+ if (options.ignoreKeys.enabled && options.ignoreKeys.values.has(key)) return false;
1979
+ return true;
1980
+ }
1981
+ function getEqualOptions(input) {
1982
+ const options = {
1983
+ ignoreCase: false,
1984
+ ignoreExpressions: {
1985
+ enabled: false,
1986
+ values: []
1987
+ },
1988
+ ignoreKeys: {
1989
+ enabled: false,
1990
+ values: /* @__PURE__ */ new Set()
1991
+ },
1992
+ relaxedNullish: false
1993
+ };
1994
+ if (typeof input === "boolean") {
1995
+ options.ignoreCase = input;
1996
+ return options;
1997
+ }
1998
+ if (!isPlainObject(input)) return options;
1999
+ options.ignoreCase = typeof input.ignoreCase === "boolean" ? input.ignoreCase : false;
2000
+ options.ignoreExpressions.values = (Array.isArray(input.ignoreKeys) ? input.ignoreKeys : [input.ignoreKeys]).filter((key) => key instanceof RegExp);
2001
+ options.ignoreKeys.values = new Set((Array.isArray(input.ignoreKeys) ? input.ignoreKeys : [input.ignoreKeys]).filter((key) => typeof key === "string"));
2002
+ options.ignoreExpressions.enabled = options.ignoreExpressions.values.length > 0;
2003
+ options.ignoreKeys.enabled = options.ignoreKeys.values.size > 0;
2004
+ options.relaxedNullish = input.relaxedNullish === true;
2005
+ return options;
2006
+ }
2007
+ var ARRAY_PEEK_PERCENTAGE = 10;
2008
+ var ARRAY_THRESHOLD = 100;
2009
+ var FilterManager = class {
2010
+ handlers = Object.freeze({
2011
+ add: (item) => this.add(item),
2012
+ clear: () => this.clear(),
2013
+ remove: (value) => this.remove(value),
2014
+ set: (items) => this.set(items)
2015
+ });
2016
+ items = {};
2017
+ constructor(managers) {
2018
+ this.managers = managers;
2019
+ }
2020
+ add(item) {
2021
+ if (this.items[item.field] == null) this.items[item.field] = [];
2022
+ else if (this.items[item.field].findIndex((existing) => equal(existing, item)) !== -1) return;
2023
+ this.items[item.field].push(item);
2024
+ this.filter();
2025
+ }
2026
+ clear() {
2027
+ if (Object.keys(this.items).length > 0) {
2028
+ this.items = {};
2029
+ this.filter();
2030
+ }
2031
+ }
2032
+ destroy() {
2033
+ this.handlers = void 0;
2034
+ this.items = {};
2035
+ }
2036
+ filter() {
2037
+ const { managers } = this;
2038
+ const filtered = [];
2039
+ const filters = Object.entries(this.items);
2040
+ const keysLength = managers.data.values.keys.original.length;
2041
+ rowLoop: for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
2042
+ const key = managers.data.values.keys.original[keyIndex];
2043
+ const row = managers.data.values.objects.mapped.get(key);
2044
+ if (row == null) continue;
2045
+ filterLoop: for (let filterIndex = 0; filterIndex < filters.length; filterIndex += 1) {
2046
+ const [field, items] = filters[filterIndex];
2047
+ const value = row[field];
2048
+ for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) {
2049
+ const filter = items[itemIndex];
2050
+ if (comparators[filter.comparison](value, filter.value)) continue filterLoop;
2051
+ }
2052
+ continue rowLoop;
2053
+ }
2054
+ filtered.push(key);
2055
+ }
2056
+ managers.data.values.keys.active = filtered;
2057
+ if (managers.sort.items.length > 0) managers.sort.sort();
2058
+ else managers.render.update(true, true);
2059
+ }
2060
+ remove(value) {
2061
+ if (typeof value === "string") {
2062
+ if (this.items[value] == null) return;
2063
+ this.items = {};
2064
+ } else {
2065
+ const { field } = value;
2066
+ if (this.items[field] == null) return;
2067
+ if (this.items[field].findIndex((item) => equal(item, value)) === -1) return;
2068
+ }
2069
+ this.filter();
2070
+ }
2071
+ set(items) {
2072
+ const keyed = {};
2073
+ const { length } = items;
2074
+ for (let index = 0; index < length; index += 1) {
2075
+ const item = items[index];
2076
+ keyed[item.field] ??= [];
2077
+ keyed[item.field].push(item);
2078
+ }
2079
+ this.items = keyed;
2080
+ this.filter();
2081
+ }
2082
+ };
2083
+ const comparators = {
2084
+ contains: (row, filter) => includes(getString(row), getString(filter), true),
2085
+ "ends-with": (row, filter) => endsWith(getString(row), getString(filter), true),
2086
+ equals: (row, filter) => equalizer(row, filter),
2087
+ "greater-than": (row, filter) => getNumber(row) > getNumber(filter),
2088
+ "greater-than-or-equal": (row, filter) => getNumber(row) >= getNumber(filter),
2089
+ "less-than": (row, filter) => getNumber(row) < getNumber(filter),
2090
+ "less-than-or-equal": (row, filter) => getNumber(row) <= getNumber(filter),
2091
+ "not-contains": (row, filter) => !includes(getString(row), getString(filter), true),
2092
+ "not-equals": (row, filter) => !equalizer(row, filter),
2093
+ "starts-with": (row, filter) => startsWith(getString(row), getString(filter), true)
2094
+ };
2095
+ const equalizer = equal.initialize({ ignoreCase: true });
1184
2096
  function removeRow(pool, row) {
1185
2097
  if (row.element != null) {
1186
2098
  row.element.innerHTML = "";
@@ -1191,18 +2103,26 @@ function removeRow(pool, row) {
1191
2103
  row.cells = {};
1192
2104
  }
1193
2105
  function renderRow(managers, row) {
1194
- const element = row.element ?? managers.virtualization.pool.rows.shift() ?? createRow();
2106
+ const element = row.element ?? managers.render.pool.rows.shift() ?? createRow();
1195
2107
  row.element = element;
1196
- element.dataset.key = String(row.key);
1197
2108
  element.innerHTML = "";
2109
+ const selected = managers.selection.items.has(row.key);
2110
+ setAttributes(element, {
2111
+ "aria-selected": String(selected),
2112
+ "data-event": "row",
2113
+ "data-key": String(row.key)
2114
+ });
2115
+ element.classList.add("tabela__row--body");
2116
+ if (selected) element.classList.add("tabela__row--selected");
2117
+ else element.classList.remove("tabela__row--selected");
1198
2118
  const columns = managers.column.items;
1199
2119
  const { length } = columns;
1200
2120
  const data = managers.data.values.objects.mapped.get(row.key);
1201
2121
  if (data == null) return;
1202
2122
  for (let index = 0; index < length; index += 1) {
1203
2123
  const { options } = columns[index];
1204
- managers.virtualization.pool.cells[options.field] ??= [];
1205
- const cell = managers.virtualization.pool.cells[columns[index].options.field].shift() ?? createCell(options.width);
2124
+ managers.render.pool.cells[options.field] ??= [];
2125
+ const cell = managers.render.pool.cells[columns[index].options.field].shift() ?? createCell(options.width);
1206
2126
  cell.textContent = String(data[options.field]);
1207
2127
  row.cells[options.field] = cell;
1208
2128
  element.append(cell);
@@ -1223,6 +2143,9 @@ var RowManager = class {
1223
2143
  this.height = rowHeight;
1224
2144
  }
1225
2145
  destroy() {
2146
+ const components = [...this.components.values()];
2147
+ const { length } = components;
2148
+ for (let index = 0; index < length; index += 1) removeRow(this.managers.render.pool, components[index]);
1226
2149
  this.components.clear();
1227
2150
  }
1228
2151
  get(key) {
@@ -1237,13 +2160,210 @@ var RowManager = class {
1237
2160
  return this.components.has(key);
1238
2161
  }
1239
2162
  remove(key) {
1240
- this.components.delete(key);
2163
+ const row = this.components.get(key);
2164
+ if (row != null) {
2165
+ removeRow(this.managers.render.pool, row);
2166
+ this.components.delete(key);
2167
+ }
1241
2168
  }
1242
2169
  update(key) {
1243
2170
  const row = this.components.get(key);
1244
2171
  if (row != null) renderRow(this.managers, row);
1245
2172
  }
1246
2173
  };
2174
+ function getKey(value) {
2175
+ if (typeof value === "number") return value;
2176
+ if (typeof value !== "string") return;
2177
+ return integerExpression.test(value) ? Number.parseInt(value, 10) : value;
2178
+ }
2179
+ const integerExpression = /^\d+$/;
2180
+ const dragStyling = toggleStyles(document.body, {
2181
+ userSelect: "none",
2182
+ webkitUserSelect: "none"
2183
+ });
2184
+ var SelectionManager = class {
2185
+ handlers = Object.freeze({
2186
+ clear: () => this.clear(),
2187
+ deselect: (keys) => this.deselect(keys),
2188
+ select: (keys) => this.select(keys),
2189
+ toggle: () => this.toggle()
2190
+ });
2191
+ items = /* @__PURE__ */ new Set();
2192
+ last;
2193
+ constructor(element, managers) {
2194
+ this.element = element;
2195
+ this.managers = managers;
2196
+ mapped.set(element, this);
2197
+ }
2198
+ clear() {
2199
+ if (this.items.size === 0) return;
2200
+ const removed = [...this.items];
2201
+ this.items.clear();
2202
+ this.update(removed);
2203
+ }
2204
+ deselect(keys) {
2205
+ const { length } = keys;
2206
+ const removed = [];
2207
+ for (let index = 0; index < length; index += 1) {
2208
+ const key = keys[index];
2209
+ if (this.items.delete(key)) removed.push(key);
2210
+ }
2211
+ if (removed.length > 0) this.update(removed);
2212
+ }
2213
+ destroy() {
2214
+ mapped.delete(this.element);
2215
+ this.handlers = void 0;
2216
+ this.element = void 0;
2217
+ this.items = void 0;
2218
+ }
2219
+ handle(event, target) {
2220
+ const key = getKey(target.getAttribute("data-key"));
2221
+ if (key == null) return;
2222
+ const { items } = this;
2223
+ if (event.shiftKey) {
2224
+ if (this.last == null) {
2225
+ this.last = key;
2226
+ return;
2227
+ }
2228
+ this.range(this.last, key);
2229
+ this.last = key;
2230
+ return;
2231
+ }
2232
+ this.last = key;
2233
+ if (event.ctrlKey || event.metaKey) {
2234
+ if (items.has(key)) this.deselect([key]);
2235
+ else this.select([key]);
2236
+ return;
2237
+ }
2238
+ if (items.has(key)) if (items.size === 1) this.clear();
2239
+ else this.set([key]);
2240
+ else this.set([key]);
2241
+ }
2242
+ range(from, to) {
2243
+ const keyed = isKey(from) && isKey(to);
2244
+ const fromKey = keyed ? from : getKey(from.getAttribute("data-key"));
2245
+ const toKey = keyed ? to : getKey(to.getAttribute("data-key"));
2246
+ if (fromKey === toKey) return;
2247
+ const keys = this.managers.data.values.keys.active ?? this.managers.data.values.keys.original;
2248
+ const fromIndex = keys.indexOf(fromKey);
2249
+ const toIndex = keys.indexOf(toKey);
2250
+ if (fromIndex === -1 || toIndex === -1) return;
2251
+ const [start, end] = fromIndex < toIndex ? [fromIndex, toIndex] : [toIndex, fromIndex];
2252
+ const selected = [];
2253
+ for (let index = start; index <= end; index += 1) selected.push(keys[index]);
2254
+ if (keyed) this.select(selected);
2255
+ else this.set(selected);
2256
+ }
2257
+ select(keys) {
2258
+ const { length } = keys;
2259
+ let update = false;
2260
+ for (let index = 0; index < length; index += 1) {
2261
+ const key = keys[index];
2262
+ if (!this.items.has(key)) {
2263
+ this.items.add(key);
2264
+ update = true;
2265
+ }
2266
+ }
2267
+ if (update) this.update([]);
2268
+ }
2269
+ set(keys) {
2270
+ const { items } = this;
2271
+ const removed = [...items].filter((key) => !keys.includes(key));
2272
+ const added = keys.filter((key) => !items.has(key));
2273
+ if (removed.length === 0 && added.length === 0) return;
2274
+ this.items = new Set(keys);
2275
+ this.update(removed);
2276
+ }
2277
+ toggle() {
2278
+ const { items, managers } = this;
2279
+ const all = managers.data.values.keys.active ?? managers.data.values.keys.original;
2280
+ if (items.size === all.length) this.clear();
2281
+ else this.select(all);
2282
+ }
2283
+ update(removed) {
2284
+ const items = [...removed.map((key) => ({
2285
+ key,
2286
+ removed: true
2287
+ })), ...[...this.items].map((key) => ({
2288
+ key,
2289
+ removed: false
2290
+ }))];
2291
+ const { length } = items;
2292
+ for (let index = 0; index < length; index += 1) {
2293
+ const { key, removed } = items[index];
2294
+ const row = this.managers.row.get(key);
2295
+ if (row == null || row.element == null) continue;
2296
+ setAttribute(row.element, "aria-selected", String(!removed));
2297
+ if (removed) row.element.classList.remove("tabela__row--selected");
2298
+ else row.element.classList.add("tabela__row--selected");
2299
+ }
2300
+ }
2301
+ };
2302
+ function getPlaceholder() {
2303
+ placeholder ??= createElement("div", { className: "tabela__selection--placeholder" }, {}, {});
2304
+ return placeholder;
2305
+ }
2306
+ function onMouseDown(event) {
2307
+ if (shifted) {
2308
+ const row = findAncestor(event.target, ".tabela__row--body");
2309
+ if (!(row instanceof HTMLElement)) return;
2310
+ startElement = row;
2311
+ startPosition = getPosition(event);
2312
+ dragStyling.set();
2313
+ }
2314
+ }
2315
+ function onMouseMove(event) {
2316
+ if (startElement == null) return;
2317
+ const currentPosition = getPosition(event);
2318
+ if (currentPosition == null || startPosition == null) return;
2319
+ const element = getPlaceholder();
2320
+ if (element.parentElement == null) document.body.append(element);
2321
+ const { x: cX, y: cY } = currentPosition;
2322
+ const { x: sX, y: sY } = startPosition;
2323
+ const top = Math.min(cY, sY);
2324
+ const left = Math.min(cX, sX);
2325
+ const width = Math.abs(cX - sX);
2326
+ const height = Math.abs(cY - sY);
2327
+ element.style.inset = `${top}px ${window.innerWidth - left - width}px ${window.innerHeight - top - height}px ${left}px`;
2328
+ }
2329
+ function onMouseUp(event) {
2330
+ if (startElement == null) return;
2331
+ if (!event.shiftKey) {
2332
+ shifted = false;
2333
+ dragStyling.remove();
2334
+ }
2335
+ getPlaceholder().remove();
2336
+ const row = findAncestor(event.target, ".tabela__row--body");
2337
+ if (row instanceof HTMLElement) {
2338
+ endElement = row;
2339
+ const endTable = findAncestor(endElement, ".tabela");
2340
+ const startTable = findAncestor(startElement, ".tabela");
2341
+ if (startTable != null && startTable === endTable) mapped.get(startTable)?.range(startElement, endElement);
2342
+ }
2343
+ endElement = void 0;
2344
+ startElement = void 0;
2345
+ startPosition = void 0;
2346
+ }
2347
+ function onShift(event, value) {
2348
+ if (event.key === "Shift") shifted = value;
2349
+ }
2350
+ function onShiftDown(event) {
2351
+ onShift(event, true);
2352
+ }
2353
+ function onShiftUp(event) {
2354
+ onShift(event, false);
2355
+ }
2356
+ const mapped = /* @__PURE__ */ new WeakMap();
2357
+ let shifted = false;
2358
+ let endElement;
2359
+ let placeholder;
2360
+ let startPosition;
2361
+ let startElement;
2362
+ on(document, "keydown", onShiftDown);
2363
+ on(document, "keyup", onShiftUp);
2364
+ on(document, "mousedown", onMouseDown);
2365
+ on(document, "mousemove", onMouseMove);
2366
+ on(document, "mouseup", onMouseUp);
1247
2367
  var SortManager = class {
1248
2368
  handlers = Object.freeze({
1249
2369
  add: (field, direction) => this.add(field, direction),
@@ -1267,13 +2387,19 @@ var SortManager = class {
1267
2387
  addOrSet(event, field) {
1268
2388
  if (event.ctrlKey || event.metaKey) this.add(field);
1269
2389
  else this.set([{
1270
- key: field,
2390
+ field,
1271
2391
  direction: "ascending"
1272
2392
  }]);
1273
2393
  }
1274
2394
  clear() {
2395
+ if (this.items.length > 0) {
2396
+ this.items.length = 0;
2397
+ this.sort();
2398
+ }
2399
+ }
2400
+ destroy() {
2401
+ this.handlers = void 0;
1275
2402
  this.items.length = 0;
1276
- this.sort();
1277
2403
  }
1278
2404
  flip(field) {
1279
2405
  const item = this.items.find((item) => item.key === field);
@@ -1293,14 +2419,17 @@ var SortManager = class {
1293
2419
  else this.clear();
1294
2420
  }
1295
2421
  set(items) {
1296
- this.items.splice(0, this.items.length, ...items);
2422
+ this.items.splice(0, this.items.length, ...items.map((item) => ({
2423
+ key: item.field,
2424
+ direction: item.direction
2425
+ })));
1297
2426
  this.sort();
1298
2427
  }
1299
2428
  sort() {
1300
2429
  const { items, managers } = this;
1301
- managers.data.values.keys.active = items.length === 0 ? void 0 : sort(managers.data.values.objects.array, items).map((row) => row[managers.data.field]);
1302
- managers.virtualization.update(true, true);
1303
- for (const column of managers.column.items) {
2430
+ const { length } = managers.column.items;
2431
+ for (let index = 0; index < length; index += 1) {
2432
+ const column = managers.column.items[index];
1304
2433
  const sorterIndex = items.findIndex((item) => item.key === column.options.field);
1305
2434
  const sorterItem = items[sorterIndex];
1306
2435
  setAttributes(column.elements.wrapper, {
@@ -1309,6 +2438,8 @@ var SortManager = class {
1309
2438
  });
1310
2439
  setAttribute(column.elements.sorter, "data-sort-position", sorterIndex > -1 && items.length > 1 ? sorterIndex + 1 : void 0);
1311
2440
  }
2441
+ managers.data.values.keys.active = items.length === 0 ? void 0 : sort(managers.data.values.keys.active?.map((key) => managers.data.values.objects.mapped.get(key)) ?? managers.data.values.objects.array, items).map((row) => row[managers.data.field]);
2442
+ managers.render.update(true, true);
1312
2443
  }
1313
2444
  toggle(event, field, direction) {
1314
2445
  switch (direction) {
@@ -1328,12 +2459,12 @@ function getRange(down) {
1328
2459
  const { components, managers } = this;
1329
2460
  const { clientHeight, scrollTop } = components.body.elements.group;
1330
2461
  const first = Math.floor(scrollTop / managers.row.height);
1331
- const last = Math.min(managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length - 1, Math.ceil((scrollTop + clientHeight) / managers.row.height) - 1);
2462
+ const last = Math.min((managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length) - 1, Math.ceil((scrollTop + clientHeight) / managers.row.height) - 1);
1332
2463
  const before = Math.ceil(clientHeight / managers.row.height) * (down ? 1 : 2);
1333
2464
  const after = Math.ceil(clientHeight / managers.row.height) * (down ? 2 : 1);
1334
2465
  const start = Math.max(0, first - before);
1335
2466
  return {
1336
- end: Math.min(managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length - 1, last + after),
2467
+ end: Math.min((managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length) - 1, last + after),
1337
2468
  start
1338
2469
  };
1339
2470
  }
@@ -1348,7 +2479,7 @@ function onScroll() {
1348
2479
  this.state.active = true;
1349
2480
  }
1350
2481
  }
1351
- var VirtualizationManager = class {
2482
+ var RenderManager = class {
1352
2483
  fragment;
1353
2484
  listener;
1354
2485
  pool = {
@@ -1366,21 +2497,26 @@ var VirtualizationManager = class {
1366
2497
  this.listener = on(components.body.elements.group, "scroll", onScroll.bind(this));
1367
2498
  }
1368
2499
  destroy() {
1369
- this.listener();
1370
- for (const [index, row] of this.visible) {
1371
- removeRow(this.pool, row);
1372
- this.visible.delete(index);
1373
- }
1374
- this.pool.cells = {};
1375
- this.pool.rows = [];
2500
+ const { listener, pool, visible } = this;
2501
+ listener();
2502
+ visible.clear();
2503
+ pool.cells = {};
2504
+ pool.rows = [];
2505
+ this.listener = void 0;
2506
+ this.visible = void 0;
1376
2507
  }
1377
2508
  removeCells(fields) {
2509
+ const { managers, pool, visible } = this;
1378
2510
  const { length } = fields;
1379
- for (let index = 0; index < length; index += 1) delete this.pool.cells[fields[index]];
1380
- for (const [, row] of this.visible) for (let index = 0; index < length; index += 1) {
1381
- row.cells[fields[index]].innerHTML = "";
1382
- row.cells[fields[index]].remove();
1383
- delete row.cells[fields[index]];
2511
+ for (let index = 0; index < length; index += 1) delete pool.cells[fields[index]];
2512
+ for (const [, key] of visible) {
2513
+ const row = managers.row.get(key);
2514
+ if (row == null || row.element == null) continue;
2515
+ for (let index = 0; index < length; index += 1) {
2516
+ row.cells[fields[index]].innerHTML = "";
2517
+ row.cells[fields[index]].remove();
2518
+ delete row.cells[fields[index]];
2519
+ }
1384
2520
  }
1385
2521
  }
1386
2522
  getFragment() {
@@ -1395,11 +2531,11 @@ var VirtualizationManager = class {
1395
2531
  const range = getRange.call(this, down);
1396
2532
  for (let index = range.start; index <= range.end; index += 1) indices.add(index);
1397
2533
  let remove = rerender ?? false;
1398
- for (const [index, row] of visible) {
1399
- if (!managers.row.has(row.key) || !indices.has(index)) remove = true;
1400
- if (remove) {
2534
+ for (const [index, key] of visible) {
2535
+ const row = managers.row.get(key);
2536
+ if (remove || row == null || !indices.has(index)) {
1401
2537
  visible.delete(index);
1402
- removeRow(pool, row);
2538
+ if (row != null) removeRow(pool, row);
1403
2539
  }
1404
2540
  }
1405
2541
  const fragment = this.getFragment();
@@ -1407,11 +2543,12 @@ var VirtualizationManager = class {
1407
2543
  let count = 0;
1408
2544
  for (let index = range.start; index <= range.end; index += 1) {
1409
2545
  if (visible.has(index)) continue;
1410
- const row = managers.row.get(keys[index]);
2546
+ const key = keys[index];
2547
+ const row = managers.row.get(key);
1411
2548
  if (row == null) continue;
1412
2549
  count += 1;
1413
2550
  renderRow(managers, row);
1414
- visible.set(index, row);
2551
+ visible.set(index, key);
1415
2552
  if (row.element != null) {
1416
2553
  row.element.style.transform = `translateY(${index * managers.row.height}px)`;
1417
2554
  fragment.append(row.element);
@@ -1432,11 +2569,15 @@ var Tabela = class {
1432
2569
  column: void 0,
1433
2570
  data: void 0,
1434
2571
  event: void 0,
2572
+ filter: void 0,
2573
+ render: void 0,
1435
2574
  row: void 0,
1436
- sort: void 0,
1437
- virtualization: void 0
2575
+ selection: void 0,
2576
+ sort: void 0
1438
2577
  };
1439
2578
  data;
2579
+ filter;
2580
+ selection;
1440
2581
  sort;
1441
2582
  get key() {
1442
2583
  return this.#key;
@@ -1453,13 +2594,17 @@ var Tabela = class {
1453
2594
  this.#components.footer = new FooterComponent();
1454
2595
  this.#managers.column = new ColumnManager(this.#managers, this.#components, options.columns);
1455
2596
  this.#managers.data = new DataManager(this.#managers, this.#components, options.key);
1456
- this.#managers.event = new EventManager(this.#managers, this.#element);
2597
+ this.#managers.event = new EventManager(this.#element, this.#managers);
2598
+ this.#managers.filter = new FilterManager(this.#managers);
2599
+ this.#managers.render = new RenderManager(this.#managers, this.#components);
1457
2600
  this.#managers.row = new RowManager(this.#managers, options.rowHeight);
2601
+ this.#managers.selection = new SelectionManager(this.#element, this.#managers);
1458
2602
  this.#managers.sort = new SortManager(this.#managers);
1459
- this.#managers.virtualization = new VirtualizationManager(this.#managers, this.#components);
1460
2603
  element.append(this.#components.header.elements.group, this.#components.body.elements.group, this.#components.footer.elements.group);
1461
2604
  this.#managers.data.set(options.data);
1462
2605
  this.data = this.#managers.data.handlers;
2606
+ this.filter = this.#managers.filter.handlers;
2607
+ this.selection = this.#managers.selection.handlers;
1463
2608
  this.sort = this.#managers.sort.handlers;
1464
2609
  }
1465
2610
  destroy() {
@@ -1471,8 +2616,11 @@ var Tabela = class {
1471
2616
  components.header.destroy();
1472
2617
  managers.column.destroy();
1473
2618
  managers.data.destroy();
2619
+ managers.event.destroy();
2620
+ managers.filter.destroy();
2621
+ managers.render.destroy();
1474
2622
  managers.row.destroy();
1475
- managers.virtualization.destroy();
2623
+ managers.sort.destroy();
1476
2624
  element.innerHTML = "";
1477
2625
  element.role = "";
1478
2626
  element.classList.remove("tabela");