@oscarpalmer/tabela 0.13.0 → 0.15.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 (108) hide show
  1. package/dist/components/body.component.d.mts +10 -1
  2. package/dist/components/body.component.mjs +8 -6
  3. package/dist/components/column.component.d.mts +15 -1
  4. package/dist/components/column.component.mjs +12 -10
  5. package/dist/components/footer.component.d.mts +12 -1
  6. package/dist/components/footer.component.mjs +6 -6
  7. package/dist/components/group.component.d.mts +19 -1
  8. package/dist/components/group.component.mjs +17 -11
  9. package/dist/components/header.component.d.mts +12 -1
  10. package/dist/components/header.component.mjs +5 -5
  11. package/dist/components/row.component.d.mts +14 -1
  12. package/dist/components/row.component.mjs +21 -17
  13. package/dist/helpers/dom.helpers.d.mts +3 -3
  14. package/dist/helpers/dom.helpers.mjs +12 -11
  15. package/dist/helpers/misc.helpers.d.mts +7 -1
  16. package/dist/helpers/misc.helpers.mjs +12 -1
  17. package/dist/index.d.mts +1 -1
  18. package/dist/managers/column.manager.d.mts +16 -1
  19. package/dist/managers/column.manager.mjs +7 -7
  20. package/dist/managers/data.manager.d.mts +26 -1
  21. package/dist/managers/data.manager.mjs +122 -88
  22. package/dist/managers/event.manager.d.mts +17 -1
  23. package/dist/managers/event.manager.mjs +35 -10
  24. package/dist/managers/filter.manager.d.mts +17 -1
  25. package/dist/managers/filter.manager.mjs +43 -35
  26. package/dist/managers/group.manager.d.mts +26 -1
  27. package/dist/managers/group.manager.mjs +36 -16
  28. package/dist/managers/navigation.manager.d.mts +15 -2
  29. package/dist/managers/navigation.manager.mjs +38 -34
  30. package/dist/managers/render.manager.d.mts +18 -1
  31. package/dist/managers/render.manager.mjs +44 -31
  32. package/dist/managers/row.manager.d.mts +18 -1
  33. package/dist/managers/row.manager.mjs +1 -1
  34. package/dist/managers/selection.manager.d.mts +22 -1
  35. package/dist/managers/selection.manager.mjs +26 -23
  36. package/dist/managers/sort.manager.d.mts +22 -1
  37. package/dist/managers/sort.manager.mjs +71 -49
  38. package/dist/managers/style.manager.d.mts +8 -1
  39. package/dist/managers/style.manager.mjs +57 -25
  40. package/dist/models/body.model.d.mts +6 -1
  41. package/dist/models/column.model.d.mts +13 -2
  42. package/dist/models/data.model.d.mts +28 -2
  43. package/dist/models/dom.model.d.mts +19 -0
  44. package/dist/models/dom.model.mjs +19 -0
  45. package/dist/models/event.model.d.mts +99 -0
  46. package/dist/models/event.model.mjs +53 -0
  47. package/dist/models/filter.model.d.mts +26 -2
  48. package/dist/models/filter.model.mjs +13 -1
  49. package/dist/models/footer.model.d.mts +7 -1
  50. package/dist/models/group.model.d.mts +19 -2
  51. package/dist/models/group.model.mjs +5 -1
  52. package/dist/models/header.model.d.mts +6 -1
  53. package/dist/models/render.model.d.mts +22 -2
  54. package/dist/models/selection.model.d.mts +11 -1
  55. package/dist/models/sort.model.d.mts +19 -2
  56. package/dist/models/sort.model.mjs +5 -1
  57. package/dist/models/style.model.d.mts +27 -21
  58. package/dist/models/style.model.mjs +27 -21
  59. package/dist/models/tabela.model.d.mts +45 -1
  60. package/dist/models/tabela.options.d.mts +13 -1
  61. package/dist/tabela.d.mts +9 -8
  62. package/dist/tabela.full.mjs +1083 -574
  63. package/dist/tabela.mjs +19 -19
  64. package/package.json +2 -4
  65. package/src/components/body.component.ts +10 -7
  66. package/src/components/column.component.ts +20 -16
  67. package/src/components/footer.component.ts +7 -10
  68. package/src/components/group.component.ts +39 -13
  69. package/src/components/header.component.ts +6 -5
  70. package/src/components/row.component.ts +27 -19
  71. package/src/helpers/dom.helpers.ts +18 -22
  72. package/src/helpers/misc.helpers.ts +17 -0
  73. package/src/managers/column.manager.ts +9 -9
  74. package/src/managers/data.manager.ts +196 -107
  75. package/src/managers/event.manager.ts +69 -12
  76. package/src/managers/filter.manager.ts +70 -41
  77. package/src/managers/group.manager.ts +60 -18
  78. package/src/managers/navigation.manager.ts +46 -49
  79. package/src/managers/render.manager.ts +60 -34
  80. package/src/managers/row.manager.ts +1 -1
  81. package/src/managers/selection.manager.ts +37 -35
  82. package/src/managers/sort.manager.ts +114 -72
  83. package/src/managers/style.manager.ts +73 -25
  84. package/src/models/column.model.ts +4 -8
  85. package/src/models/data.model.ts +13 -14
  86. package/src/models/dom.model.ts +31 -0
  87. package/src/models/event.model.ts +175 -0
  88. package/src/models/filter.model.ts +22 -2
  89. package/src/models/group.model.ts +13 -0
  90. package/src/models/render.model.ts +6 -0
  91. package/src/models/sort.model.ts +11 -5
  92. package/src/models/style.model.ts +32 -20
  93. package/src/models/tabela.model.ts +1 -0
  94. package/src/tabela.ts +26 -24
  95. package/dist/body.component-_VDOpJhV.d.mts +0 -10
  96. package/dist/body.model-2iwsovAV.d.mts +0 -7
  97. package/dist/column.component-Bx46r3JI.d.mts +0 -16
  98. package/dist/column.model-D-aw4EU4.d.mts +0 -16
  99. package/dist/filter.model-7ukJrtil.d.mts +0 -16
  100. package/dist/footer.component-Curiab8j.d.mts +0 -12
  101. package/dist/footer.model-DhqoS6ds.d.mts +0 -8
  102. package/dist/group.component-Cq1YYbfJ.d.mts +0 -285
  103. package/dist/group.model-BsKFwHbt.d.mts +0 -10
  104. package/dist/header.component-BjjlpZIg.d.mts +0 -12
  105. package/dist/header.model-DN_KzUCV.d.mts +0 -7
  106. package/dist/selection.model-rwQe9fco.d.mts +0 -12
  107. package/dist/sort.model-CauImaLu.d.mts +0 -15
  108. package/dist/tabela.options-RkZvfptB.d.mts +0 -14
@@ -23,29 +23,13 @@ new Set([
23
23
  Node.DOCUMENT_TYPE_NODE
24
24
  ]);
25
25
  //#endregion
26
- //#region node_modules/@oscarpalmer/atoms/dist/internal/is.mjs
27
- /**
28
- * Is the value a constructor function?
29
- * @param value Value to check
30
- * @returns `true` if the value is a constructor function, otherwise `false`
31
- */
32
- function isConstructor(value) {
33
- return typeof value === "function" && value.prototype?.constructor === value;
34
- }
35
- /**
36
- * Is the value a key?
37
- * @param value Value to check
38
- * @returns `true` if the value is a `Key` _(`number` or `string`)_, otherwise `false`
39
- */
40
- function isKey(value) {
41
- return typeof value === "number" || typeof value === "string";
42
- }
26
+ //#region node_modules/@oscarpalmer/toretto/node_modules/@oscarpalmer/atoms/dist/internal/is.mjs
43
27
  /**
44
28
  * Is the value a number?
45
29
  * @param value Value to check
46
30
  * @returns `true` if the value is a `number`, otherwise `false`
47
31
  */
48
- function isNumber(value) {
32
+ function isNumber$1(value) {
49
33
  return typeof value === "number" && !Number.isNaN(value);
50
34
  }
51
35
  /**
@@ -53,37 +37,15 @@ function isNumber(value) {
53
37
  * @param value Value to check
54
38
  * @returns `true` if the value is a plain object, otherwise `false`
55
39
  */
56
- function isPlainObject(value) {
40
+ function isPlainObject$1(value) {
57
41
  if (value === null || typeof value !== "object") return false;
58
42
  if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
59
43
  const prototype = Object.getPrototypeOf(value);
60
44
  return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
61
45
  }
62
- /**
63
- * Is the value a typed array?
64
- * @param value Value to check
65
- * @returns `true` if the value is a typed array, otherwise `false`
66
- */
67
- function isTypedArray(value) {
68
- TYPED_ARRAYS ??= new Set([
69
- Int8Array,
70
- Uint8Array,
71
- Uint8ClampedArray,
72
- Int16Array,
73
- Uint16Array,
74
- Int32Array,
75
- Uint32Array,
76
- Float32Array,
77
- Float64Array,
78
- BigInt64Array,
79
- BigUint64Array
80
- ]);
81
- return TYPED_ARRAYS.has(value?.constructor);
82
- }
83
- let TYPED_ARRAYS;
84
46
  //#endregion
85
- //#region node_modules/@oscarpalmer/atoms/dist/internal/array/compact.mjs
86
- function compact(array, strict) {
47
+ //#region node_modules/@oscarpalmer/toretto/node_modules/@oscarpalmer/atoms/dist/internal/array/compact.mjs
48
+ function compact$1(array, strict) {
87
49
  if (!Array.isArray(array)) return [];
88
50
  if (strict === true) return array.filter(Boolean);
89
51
  const { length } = array;
@@ -95,53 +57,49 @@ function compact(array, strict) {
95
57
  return compacted;
96
58
  }
97
59
  //#endregion
98
- //#region node_modules/@oscarpalmer/atoms/dist/internal/string.mjs
60
+ //#region node_modules/@oscarpalmer/toretto/node_modules/@oscarpalmer/atoms/dist/internal/string.mjs
99
61
  /**
100
62
  * Get the string value from any value
101
63
  * @param value Original value
102
64
  * @returns String representation of the value
103
65
  */
104
- function getString(value) {
66
+ function getString$1(value) {
105
67
  if (typeof value === "string") return value;
106
68
  if (value == null) return "";
107
- if (typeof value === "function") return getString(value());
69
+ if (typeof value === "function") return getString$1(value());
108
70
  if (typeof value !== "object") return String(value);
109
71
  const asString = String(value.valueOf?.() ?? value);
110
72
  return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
111
73
  }
112
- function ignoreKey(key) {
113
- return EXPRESSION_IGNORED.test(key);
114
- }
115
74
  /**
116
75
  * Join an array of values into a string
117
76
  * @param value Array of values
118
77
  * @param delimiter Delimiter to use between values
119
78
  * @returns Joined string
120
79
  */
121
- function join(value, delimiter) {
122
- return compact(value).map(getString).join(typeof delimiter === "string" ? delimiter : "");
80
+ function join$1(value, delimiter) {
81
+ return compact$1(value).map(getString$1).join(typeof delimiter === "string" ? delimiter : "");
123
82
  }
124
83
  /**
125
84
  * Split a string into words _(and other readable parts)_
126
85
  * @param value Original string
127
86
  * @returns Array of words found in the string
128
87
  */
129
- function words(value) {
130
- return typeof value === "string" ? value.match(EXPRESSION_WORDS) ?? [] : [];
88
+ function words$1(value) {
89
+ return typeof value === "string" ? value.match(EXPRESSION_WORDS$1) ?? [] : [];
131
90
  }
132
- const EXPRESSION_IGNORED = /(^|\.)(__proto__|constructor|prototype)(\.|$)/i;
133
- const EXPRESSION_WORDS = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
91
+ const EXPRESSION_WORDS$1 = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
134
92
  //#endregion
135
- //#region node_modules/@oscarpalmer/atoms/dist/is.mjs
93
+ //#region node_modules/@oscarpalmer/toretto/node_modules/@oscarpalmer/atoms/dist/is.mjs
136
94
  /**
137
95
  * Is the value `undefined`, `null`, or a whitespace-only string?
138
96
  * @param value Value to check
139
97
  * @returns `true` if the value is nullable or a whitespace-only string, otherwise `false`
140
98
  */
141
- function isNullableOrWhitespace(value) {
142
- return value == null || EXPRESSION_WHITESPACE.test(getString(value));
99
+ function isNullableOrWhitespace$1(value) {
100
+ return value == null || EXPRESSION_WHITESPACE$1.test(getString$1(value));
143
101
  }
144
- const EXPRESSION_WHITESPACE = /^\s*$/;
102
+ const EXPRESSION_WHITESPACE$1 = /^\s*$/;
145
103
  //#endregion
146
104
  //#region node_modules/@oscarpalmer/toretto/dist/internal/element-value.mjs
147
105
  function setElementValue(element, first, second, third, callback) {
@@ -168,13 +126,13 @@ function setElementValues(element, first, second, third, callback) {
168
126
  }
169
127
  }
170
128
  function updateElementValue(element, key, value, set, remove, isBoolean, json) {
171
- if (isBoolean ? value == null : isNullableOrWhitespace(value)) remove.call(element, key);
129
+ if (isBoolean ? value == null : isNullableOrWhitespace$1(value)) remove.call(element, key);
172
130
  else set.call(element, key, json ? JSON.stringify(value) : String(value));
173
131
  }
174
132
  //#endregion
175
133
  //#region node_modules/@oscarpalmer/toretto/dist/internal/attribute.mjs
176
134
  function isAttribute(value) {
177
- return value instanceof Attr || isPlainObject(value) && typeof value.name === "string" && "value" in value;
135
+ return value instanceof Attr || isPlainObject$1(value) && typeof value.name === "string" && "value" in value;
178
136
  }
179
137
  function updateAttribute(element, name, value, dispatch) {
180
138
  const normalizedName = name.toLowerCase();
@@ -230,7 +188,7 @@ const elementEvents = {
230
188
  };
231
189
  document.createElement("form");
232
190
  //#endregion
233
- //#region node_modules/@oscarpalmer/atoms/dist/internal/number.mjs
191
+ //#region node_modules/@oscarpalmer/toretto/node_modules/@oscarpalmer/atoms/dist/internal/number.mjs
234
192
  /**
235
193
  * Clamp a number between a minimum and maximum value
236
194
  * @param value Value to clamp
@@ -239,59 +197,33 @@ document.createElement("form");
239
197
  * @param loop If `true`, the value will loop around when smaller than the minimum or larger than the maximum _(defaults to `false`)_
240
198
  * @returns Clamped value
241
199
  */
242
- function clamp(value, minimum, maximum, loop) {
200
+ function clamp$1(value, minimum, maximum, loop) {
243
201
  if (![
244
202
  value,
245
203
  minimum,
246
204
  maximum
247
- ].every(isNumber)) return NaN;
205
+ ].every(isNumber$1)) return NaN;
248
206
  if (value < minimum) return loop === true ? maximum : minimum;
249
207
  return value > maximum ? loop === true ? minimum : maximum : value;
250
208
  }
251
- /**
252
- * Get the number value from an unknown value _(based on Lodash)_
253
- * @param value Original value
254
- * @returns Original value as a number, or `NaN` if the value is unable to be parsed
255
- */
256
- function getNumber(value) {
257
- if (typeof value === "number") return value;
258
- if (typeof value === "bigint" || typeof value === "boolean") return Number(value);
259
- if (value == null || typeof value === "symbol") return NaN;
260
- if (typeof value === "function") return getNumber(value());
261
- let parsed = value.valueOf();
262
- if (typeof parsed === "object") parsed = parsed.toString();
263
- if (typeof parsed !== "string") return getNumber(parsed);
264
- const trimmed = parsed.trim();
265
- if (trimmed.length === 0) return NaN;
266
- if (EXPRESSION_ZEROISH.test(parsed)) return 0;
267
- const isBinary = EXPRESSION_BINARY.test(trimmed);
268
- if (isBinary || EXPRESSION_OCTAL.test(trimmed)) return Number.parseInt(trimmed.slice(2), isBinary ? 2 : OCTAL_VALUE);
269
- return Number(EXPRESSION_HEX.test(trimmed) ? trimmed : trimmed.replace(EXPRESSION_UNDERSCORE, ""));
270
- }
271
- const EXPRESSION_BINARY = /^0b[01]+$/i;
272
- const EXPRESSION_HEX = /^0x[0-9a-f]+$/i;
273
- const EXPRESSION_OCTAL = /^0o[0-7]+$/i;
274
- const EXPRESSION_UNDERSCORE = /_/g;
275
- const EXPRESSION_ZEROISH = /^\s*0+\s*$/;
276
- const OCTAL_VALUE = 8;
277
209
  //#endregion
278
- //#region node_modules/@oscarpalmer/atoms/dist/internal/sized.mjs
279
- function getSizedMaximum(first, second) {
210
+ //#region node_modules/@oscarpalmer/toretto/node_modules/@oscarpalmer/atoms/dist/internal/sized.mjs
211
+ function getSizedMaximum$1(first, second) {
280
212
  let actual;
281
213
  if (typeof first === "number") actual = first;
282
- else actual = typeof second === "number" ? second : MAXIMUM_DEFAULT;
283
- return clamp(actual, 1, MAXIMUM_ABSOLUTE);
214
+ else actual = typeof second === "number" ? second : MAXIMUM_DEFAULT$1;
215
+ return clamp$1(actual, 1, MAXIMUM_ABSOLUTE$1);
284
216
  }
285
- const MAXIMUM_ABSOLUTE = 16777216;
286
- const MAXIMUM_DEFAULT = 1048576;
217
+ const MAXIMUM_ABSOLUTE$1 = 16777216;
218
+ const MAXIMUM_DEFAULT$1 = 1048576;
287
219
  //#endregion
288
- //#region node_modules/@oscarpalmer/atoms/dist/sized/map.mjs
220
+ //#region node_modules/@oscarpalmer/toretto/node_modules/@oscarpalmer/atoms/dist/sized/map.mjs
289
221
  /**
290
222
  * A Map with a maximum size
291
223
  *
292
224
  * Behavior is similar to a _LRU_-cache, where the least recently used entries are removed
293
225
  */
294
- var SizedMap = class extends Map {
226
+ var SizedMap$1 = class extends Map {
295
227
  /**
296
228
  * The maximum size of the Map
297
229
  */
@@ -306,7 +238,7 @@ var SizedMap = class extends Map {
306
238
  return this.#maximumSize;
307
239
  }
308
240
  constructor(first, second) {
309
- const maximum = getSizedMaximum(first, second);
241
+ const maximum = getSizedMaximum$1(first, second);
310
242
  super();
311
243
  this.#maximumSize = maximum;
312
244
  if (Array.isArray(first)) {
@@ -333,8 +265,8 @@ var SizedMap = class extends Map {
333
265
  }
334
266
  };
335
267
  //#endregion
336
- //#region node_modules/@oscarpalmer/atoms/dist/function/memoize.mjs
337
- var Memoized = class {
268
+ //#region node_modules/@oscarpalmer/toretto/node_modules/@oscarpalmer/atoms/dist/function/memoize.mjs
269
+ var Memoized$1 = class {
338
270
  #state;
339
271
  /**
340
272
  * Maximum cache size
@@ -349,9 +281,9 @@ var Memoized = class {
349
281
  return this.#state.cache?.size ?? NaN;
350
282
  }
351
283
  constructor(callback, options) {
352
- const cache = new SizedMap(options.cacheSize);
284
+ const cache = new SizedMap$1(options.cacheSize);
353
285
  const getter = (...parameters) => {
354
- const key = options.cacheKey?.(...parameters) ?? (parameters.length === 1 ? parameters[0] : join(parameters.map(getString), SEPARATOR));
286
+ const key = options.cacheKey?.(...parameters) ?? (parameters.length === 1 ? parameters[0] : join$1(parameters.map(getString$1), SEPARATOR$1));
355
287
  if (cache.has(key)) return cache.get(key);
356
288
  const value = callback(...parameters);
357
289
  cache.set(key, value);
@@ -410,11 +342,11 @@ var Memoized = class {
410
342
  return this.#state.getter(...parameters);
411
343
  }
412
344
  };
413
- function getMemoizationOptions(input) {
414
- const { cacheKey, cacheSize } = isPlainObject(input) ? input : {};
345
+ function getMemoizationOptions$1(input) {
346
+ const { cacheKey, cacheSize } = isPlainObject$1(input) ? input : {};
415
347
  return {
416
348
  cacheKey: typeof cacheKey === "function" ? cacheKey : void 0,
417
- cacheSize: typeof cacheSize === "number" && cacheSize > 0 ? cacheSize : DEFAULT_CACHE_SIZE
349
+ cacheSize: typeof cacheSize === "number" && cacheSize > 0 ? cacheSize : DEFAULT_CACHE_SIZE$1
418
350
  };
419
351
  }
420
352
  /**
@@ -423,13 +355,13 @@ function getMemoizationOptions(input) {
423
355
  * @param options Memoization options
424
356
  * @returns Memoized instance
425
357
  */
426
- function memoize(callback, options) {
427
- return new Memoized(callback, getMemoizationOptions(options));
358
+ function memoize$1(callback, options) {
359
+ return new Memoized$1(callback, getMemoizationOptions$1(options));
428
360
  }
429
- const DEFAULT_CACHE_SIZE = 1024;
430
- const SEPARATOR = "_";
361
+ const DEFAULT_CACHE_SIZE$1 = 1024;
362
+ const SEPARATOR$1 = "_";
431
363
  //#endregion
432
- //#region node_modules/@oscarpalmer/atoms/dist/string/case.mjs
364
+ //#region node_modules/@oscarpalmer/toretto/node_modules/@oscarpalmer/atoms/dist/string/case.mjs
433
365
  /**
434
366
  * Convert a string to camel case _(thisIsCamelCase)_
435
367
  * @param value String to convert
@@ -445,11 +377,11 @@ function camelCase(value) {
445
377
  */
446
378
  function capitalize(value) {
447
379
  if (typeof value !== "string" || value.length === 0) return "";
448
- memoizedCapitalize ??= memoize((v) => v.length === 1 ? v.toLocaleUpperCase() : `${v.charAt(0).toLocaleUpperCase()}${v.slice(1).toLocaleLowerCase()}`);
380
+ memoizedCapitalize ??= memoize$1((v) => v.length === 1 ? v.toLocaleUpperCase() : `${v.charAt(0).toLocaleUpperCase()}${v.slice(1).toLocaleLowerCase()}`);
449
381
  return memoizedCapitalize.run(value);
450
382
  }
451
383
  function toCase(type, value, capitalizeAny, capitalizeFirst) {
452
- caseMemoizers[type] ??= memoize(toCaseCallback.bind({
384
+ caseMemoizers[type] ??= memoize$1(toCaseCallback.bind({
453
385
  type,
454
386
  capitalizeAny,
455
387
  capitalizeFirst
@@ -460,7 +392,7 @@ function toCaseCallback(value) {
460
392
  if (typeof value !== "string") return "";
461
393
  if (value.length < 1) return value;
462
394
  const { capitalizeAny, capitalizeFirst, type } = this;
463
- const parts = words(value);
395
+ const parts = words$1(value);
464
396
  const partsLength = parts.length;
465
397
  const cased = [];
466
398
  for (let partIndex = 0; partIndex < partsLength; partIndex += 1) {
@@ -475,9 +407,9 @@ function toCaseCallback(value) {
475
407
  else partResult.push(capitalize(item));
476
408
  itemCount += 1;
477
409
  }
478
- cased.push(join(partResult, delimiters[type]));
410
+ cased.push(join$1(partResult, delimiters[type]));
479
411
  }
480
- return join(cased, delimiters[type]);
412
+ return join$1(cased, delimiters[type]);
481
413
  }
482
414
  const CASE_CAMEL = "camel";
483
415
  const CASE_KEBAB = "kebab";
@@ -582,35 +514,56 @@ function updateStyleProperty(element, key, value) {
582
514
  }, false, false);
583
515
  }
584
516
  //#endregion
517
+ //#region src/models/dom.model.ts
518
+ const ARIA_ACTIVEDESCENDANT = "aria-activedescendant";
519
+ const ARIA_LABEL = "aria-label";
520
+ const ARIA_SELECTED = "aria-selected";
521
+ const ARIA_SORT = "aria-sort";
522
+ const ATTRIBUTE_DATA_ACTIVE = "data-active";
523
+ const ATTRIBUTE_DATA_EVENT = "data-event";
524
+ const ATTRIBUTE_DATA_KEY = "data-key";
525
+ const ATTRIBUTE_DATA_SORT_DIRECTION = "data-sort-direction";
526
+ const ATTRIBUTE_DATA_SORT_POSITION = "data-sort-position";
527
+ const ATTRIBUTE_ROLE = "role";
528
+ const ROLE_CELL = "cell";
529
+ const ROLE_COLUMNHEADER = "columnheader";
530
+ const ROLE_ROWGROUP = "rowgroup";
531
+ const ROLE_TABLE = "table";
532
+ //#endregion
585
533
  //#region src/models/style.model.ts
586
- const CSS_TABELA = "tabela";
587
- const CSS_TABELA_CELL = "tabela__cell";
588
- const CSS_TABELA_CELL_BODY = "tabela__cell--body";
589
- const CSS_TABELA_CELL_FOOTER = "tabela__cell--footer";
590
- const CSS_TABELA_FAKER = "tabela__faker";
591
- const CSS_TABELA_HEADING = "tabela__heading";
592
- const CSS_TABELA_HEADING_CONTENT = "tabela__heading__content";
593
- const CSS_TABELA_HEADING_SORTER = "tabela__heading__sorter";
594
- const CSS_TABELA_ROW = "tabela__row";
595
- const CSS_TABELA_ROW_BODY = "tabela__row--body";
596
- const CSS_TABELA_ROW_FOOTER = "tabela__row--footer";
597
- const CSS_TABELA_ROW_GROUP = "tabela__row--group tabela__group";
598
- const CSS_TABELA_ROW_HEADER = "tabela__row--header";
599
- const CSS_TABELA_ROW_SELECTED = "tabela__row--selected";
600
- const CSS_TABELA_ROWGROUP = "tabela__rowgroup";
601
- const CSS_TABELA_ROWGROUP_BODY = "tabela__rowgroup--body";
602
- const CSS_TABELA_ROWGROUP_FOOTER = "tabela__rowgroup--footer";
603
- const CSS_TABELA_ROWGROUP_HEADER = "tabela__rowgroup--header";
604
- const CSS_TABELA_SELECTION = "tabela__selection";
605
- const CSS_TABELA_TABLE = "tabela__table";
534
+ const CSS_BUTTON = "tabela__button";
535
+ const CSS_BUTTON_GROUP = "tabela__button--group";
536
+ const CSS_CELL = "tabela__cell";
537
+ const CSS_CELL_BODY = "tabela__cell--body";
538
+ const CSS_CELL_FOOTER = "tabela__cell--footer";
539
+ const CSS_CELL_GROUP = "tabela__cell--group";
540
+ const CSS_FAKER = "tabela__faker";
541
+ const CSS_GROUP_SELECTED = "tabela__group__selected";
542
+ const CSS_GROUP_TOTAL = "tabela__group__total";
543
+ const CSS_HEADING = "tabela__heading";
544
+ const CSS_HEADING_CONTENT = "tabela__heading__content";
545
+ const CSS_HEADING_SORTER = "tabela__heading__sorter";
546
+ const CSS_ROW = "tabela__row";
547
+ const CSS_ROW_BODY = "tabela__row--body";
548
+ const CSS_ROW_FOOTER = "tabela__row--footer";
549
+ const CSS_ROW_GROUP = "tabela__row--group tabela__group";
550
+ const CSS_ROW_HEADER = "tabela__row--header";
551
+ const CSS_ROW_SELECTED = "tabela__row--selected";
552
+ const CSS_ROWGROUP = "tabela__rowgroup";
553
+ const CSS_ROWGROUP_BODY = "tabela__rowgroup--body";
554
+ const CSS_ROWGROUP_FOOTER = "tabela__rowgroup--footer";
555
+ const CSS_ROWGROUP_HEADER = "tabela__rowgroup--header";
556
+ const CSS_SELECTION = "tabela__selection";
557
+ const CSS_TABLE = "tabela__table";
558
+ const CSS_WRAPPER = "tabela";
606
559
  //#endregion
607
560
  //#region src/helpers/dom.helpers.ts
608
561
  function createCell(width, body) {
609
562
  const cell = createElement("div", {
610
- className: CSS_TABELA_CELL,
611
- role: "cell"
563
+ className: CSS_CELL,
564
+ role: ROLE_CELL
612
565
  }, {}, { width: `${width}px` });
613
- if (body ?? true) cell.classList.add(CSS_TABELA_CELL_BODY);
566
+ if (body ?? true) cell.classList.add(CSS_CELL_BODY);
614
567
  return cell;
615
568
  }
616
569
  function createElement(tagName, properties, attributes, style) {
@@ -622,41 +575,92 @@ function createElement(tagName, properties, attributes, style) {
622
575
  setStyles(element, style ?? {});
623
576
  return element;
624
577
  }
625
- function createRowGroup(withRow) {
578
+ function createRowGroup(height, withRow) {
626
579
  const group = createElement("div", {
627
- className: CSS_TABELA_ROWGROUP,
628
- role: "rowgroup"
580
+ className: CSS_ROWGROUP,
581
+ role: ROLE_ROWGROUP
629
582
  });
630
583
  if (!(withRow ?? true)) return group;
631
- const row = createRow();
584
+ const row = createRow(height);
632
585
  group.append(row);
633
586
  return {
634
587
  group,
635
588
  row
636
589
  };
637
590
  }
638
- function createRow() {
591
+ function createRow(height) {
639
592
  return createElement("div", {
640
- className: CSS_TABELA_ROW,
593
+ className: CSS_ROW,
641
594
  role: "row"
642
- }, {}, { height: "32px" });
595
+ }, {}, { height: `${height}px` });
643
596
  }
644
597
  //#endregion
598
+ //#region src/models/event.model.ts
599
+ const EVENT_BODY = "body";
600
+ const EVENT_DATA_ADD = "data:add";
601
+ const EVENT_DATA_CLEAR = "data:clear";
602
+ const EVENT_DATA_FILTERED = "data:filtered";
603
+ const EVENT_DATA_REMOVE = "data:remove";
604
+ const EVENT_DATA_SORTED = "data:sorted";
605
+ const EVENT_DATA_SYNCHRONIZE = "data:synchronize";
606
+ const EVENT_DATA_UPDATE = "data:update";
607
+ const EVENT_GROUP = "group";
608
+ const EVENT_GROUP_ADD = "group:add";
609
+ const EVENT_GROUP_CLEAR = "group:clear";
610
+ const EVENT_GROUP_REMOVE = "group:remove";
611
+ const EVENT_GROUP_TOGGLE = "group:toggle";
612
+ const EVENT_GROUP_UPDATE = "group:update";
613
+ const EVENT_HEADING = "heading";
614
+ const EVENT_SORT_ADD = "sort:add";
615
+ const EVENT_SORT_CLEAR = "sort:clear";
616
+ const EVENT_SORT_FLIP = "sort:flip";
617
+ const EVENT_SORT_REMOVE = "sort:remove";
618
+ const EVENT_SORT_SET = "sort:set";
619
+ const EVENTS_NAMES = new Set([
620
+ EVENT_DATA_ADD,
621
+ EVENT_DATA_CLEAR,
622
+ EVENT_DATA_FILTERED,
623
+ EVENT_DATA_REMOVE,
624
+ EVENT_DATA_SORTED,
625
+ EVENT_DATA_SYNCHRONIZE,
626
+ EVENT_DATA_UPDATE,
627
+ "filter:add",
628
+ "filter:clear",
629
+ "filter:remove",
630
+ EVENT_GROUP_ADD,
631
+ EVENT_GROUP_CLEAR,
632
+ EVENT_GROUP_REMOVE,
633
+ EVENT_GROUP_TOGGLE,
634
+ EVENT_GROUP_UPDATE,
635
+ "navigation:active",
636
+ "render:begin",
637
+ "render:end",
638
+ "selection:add",
639
+ "selection:clear",
640
+ "selection:remove",
641
+ "selection:toggle",
642
+ EVENT_SORT_ADD,
643
+ EVENT_SORT_CLEAR,
644
+ EVENT_SORT_FLIP,
645
+ EVENT_SORT_REMOVE,
646
+ EVENT_SORT_SET
647
+ ]);
648
+ //#endregion
645
649
  //#region src/components/body.component.ts
646
650
  function createFaker() {
647
- return createElement("div", { className: CSS_TABELA_FAKER });
651
+ return createElement("div", { className: CSS_FAKER });
648
652
  }
649
653
  var BodyComponent = class {
650
654
  elements = {
651
655
  faker: createFaker(),
652
656
  group: void 0
653
657
  };
654
- constructor() {
655
- const group = createRowGroup(false);
658
+ constructor(state) {
659
+ const group = createRowGroup(state.options.rowHeight, false);
656
660
  this.elements.group = group;
657
- group.className += ` ${CSS_TABELA_ROWGROUP_BODY}`;
661
+ group.className += ` ${CSS_ROWGROUP_BODY}`;
658
662
  group.tabIndex = 0;
659
- group.setAttribute("data-event", "body");
663
+ group.setAttribute(ATTRIBUTE_DATA_EVENT, EVENT_BODY);
660
664
  group.append(this.elements.faker);
661
665
  }
662
666
  destroy() {
@@ -668,15 +672,15 @@ var BodyComponent = class {
668
672
  //#region src/components/footer.component.ts
669
673
  var FooterComponent = class {
670
674
  elements;
671
- constructor() {
672
- const { group, row } = createRowGroup();
675
+ constructor(state) {
676
+ const { group, row } = createRowGroup(state.options.rowHeight);
673
677
  this.elements = {
674
678
  group,
675
679
  row,
676
680
  cells: []
677
681
  };
678
- group.className += ` ${CSS_TABELA_ROWGROUP_FOOTER}`;
679
- row.className += ` ${CSS_TABELA_ROW_FOOTER}`;
682
+ group.className += ` ${CSS_ROWGROUP_FOOTER}`;
683
+ row.className += ` ${CSS_ROW_FOOTER}`;
680
684
  }
681
685
  destroy() {
682
686
  this.elements.cells.length = 0;
@@ -690,7 +694,7 @@ var FooterComponent = class {
690
694
  elements.row.innerHTML = "";
691
695
  for (let index = 0; index < length; index += 1) {
692
696
  const cell = createCell(columns[index].options.width ?? 4, false);
693
- cell.className += ` ${CSS_TABELA_CELL_FOOTER}`;
697
+ cell.className += ` ${CSS_CELL_FOOTER}`;
694
698
  cell.innerHTML = "&nbsp;";
695
699
  elements.cells.push(cell);
696
700
  elements.row.append(cell);
@@ -701,14 +705,14 @@ var FooterComponent = class {
701
705
  //#region src/components/header.component.ts
702
706
  var HeaderComponent = class {
703
707
  elements;
704
- constructor() {
705
- const { group, row } = createRowGroup();
708
+ constructor(state) {
709
+ const { group, row } = createRowGroup(state.options.rowHeight);
706
710
  this.elements = {
707
711
  group,
708
712
  row
709
713
  };
710
- group.className += ` ${CSS_TABELA_ROWGROUP_HEADER}`;
711
- row.className += ` ${CSS_TABELA_ROW_HEADER}`;
714
+ group.className += ` ${CSS_ROWGROUP_HEADER}`;
715
+ row.className += ` ${CSS_ROW_HEADER}`;
712
716
  }
713
717
  destroy() {
714
718
  this.elements.group = void 0;
@@ -725,12 +729,12 @@ var ColumnComponent = class {
725
729
  elements;
726
730
  options;
727
731
  constructor(column) {
728
- const width = Number.parseInt(getComputedStyle(document.body).fontSize, 10) * (column.width ?? column.title.length * 1.5);
732
+ const width = Number.parseInt(getComputedStyle(document.body).fontSize, 10) * (column.width ?? column.label.length * 1.5);
729
733
  this.options = {
730
734
  ...column,
731
735
  width
732
736
  };
733
- this.elements = createHeading(this.options.field, this.options.title, width);
737
+ this.elements = createHeading(this.options.key, this.options.label, width);
734
738
  }
735
739
  destroy() {
736
740
  this.elements.content.remove();
@@ -740,19 +744,19 @@ var ColumnComponent = class {
740
744
  this.options = void 0;
741
745
  }
742
746
  };
743
- function createHeading(field, title, width) {
747
+ function createHeading(key, title, width) {
744
748
  const wrapper = createElement("div", {
745
- className: CSS_TABELA_HEADING,
746
- role: "columnheader"
749
+ className: CSS_HEADING,
750
+ [ATTRIBUTE_ROLE]: ROLE_COLUMNHEADER
747
751
  }, {
748
- "data-event": "heading",
749
- "data-field": field
752
+ [ATTRIBUTE_DATA_EVENT]: EVENT_HEADING,
753
+ [ATTRIBUTE_DATA_KEY]: key
750
754
  }, { width: `${width}px` });
751
755
  const content = createElement("div", {
752
- className: CSS_TABELA_HEADING_CONTENT,
756
+ className: CSS_HEADING_CONTENT,
753
757
  textContent: title
754
758
  });
755
- const sorter = createElement("div", { className: CSS_TABELA_HEADING_SORTER });
759
+ const sorter = createElement("div", { className: CSS_HEADING_SORTER });
756
760
  wrapper.append(content, sorter);
757
761
  return {
758
762
  content,
@@ -774,17 +778,17 @@ var ColumnManager = class {
774
778
  this.items = void 0;
775
779
  this.state = void 0;
776
780
  }
777
- get(field) {
778
- return this.items.find((item) => item.options.field === field);
781
+ get(key) {
782
+ return this.items.find((item) => item.options.key === key);
779
783
  }
780
784
  remove(value) {
781
785
  const { items, state } = this;
782
786
  const { components, managers } = state;
783
- const fields = (Array.isArray(value) ? value : [value]).filter((item) => typeof item === "string");
784
- const { length } = fields;
787
+ const keys = (Array.isArray(value) ? value : [value]).filter((item) => typeof item === "string");
788
+ const { length } = keys;
785
789
  if (length === 0) return;
786
- for (let fieldIndex = 0; fieldIndex < length; fieldIndex += 1) {
787
- const itemIndex = items.findIndex((component) => component.options.field === fields[fieldIndex]);
790
+ for (let keyIndex = 0; keyIndex < length; keyIndex += 1) {
791
+ const itemIndex = items.findIndex((component) => component.options.key === keys[keyIndex]);
788
792
  if (itemIndex > -1) {
789
793
  items[itemIndex].destroy();
790
794
  items.splice(itemIndex, 1);
@@ -792,7 +796,7 @@ var ColumnManager = class {
792
796
  }
793
797
  components.header.update(items);
794
798
  components.footer.update(items);
795
- managers.render.removeCells(fields);
799
+ managers.render.removeCells(keys);
796
800
  }
797
801
  set(columns) {
798
802
  const { items, state } = this;
@@ -826,6 +830,19 @@ function chunk(array, size) {
826
830
  }
827
831
  const MAX_SIZE = 5e3;
828
832
  //#endregion
833
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/array/compact.mjs
834
+ function compact(array, strict) {
835
+ if (!Array.isArray(array)) return [];
836
+ if (strict === true) return array.filter(Boolean);
837
+ const { length } = array;
838
+ const compacted = [];
839
+ for (let index = 0; index < length; index += 1) {
840
+ const item = array[index];
841
+ if (item != null) compacted.push(item);
842
+ }
843
+ return compacted;
844
+ }
845
+ //#endregion
829
846
  //#region node_modules/@oscarpalmer/atoms/dist/internal/array/callbacks.mjs
830
847
  function getArrayCallback(value) {
831
848
  switch (typeof value) {
@@ -888,6 +905,65 @@ function getParameters(original) {
888
905
  }
889
906
  const UNIQUE_THRESHOLD = 100;
890
907
  //#endregion
908
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/is.mjs
909
+ /**
910
+ * Is the value a constructor function?
911
+ * @param value Value to check
912
+ * @returns `true` if the value is a constructor function, otherwise `false`
913
+ */
914
+ function isConstructor(value) {
915
+ return typeof value === "function" && value.prototype?.constructor === value;
916
+ }
917
+ /**
918
+ * Is the value a key?
919
+ * @param value Value to check
920
+ * @returns `true` if the value is a `Key` _(`number` or `string`)_, otherwise `false`
921
+ */
922
+ function isKey(value) {
923
+ return typeof value === "number" || typeof value === "string";
924
+ }
925
+ /**
926
+ * Is the value a number?
927
+ * @param value Value to check
928
+ * @returns `true` if the value is a `number`, otherwise `false`
929
+ */
930
+ function isNumber(value) {
931
+ return typeof value === "number" && !Number.isNaN(value);
932
+ }
933
+ /**
934
+ * Is the value a plain object?
935
+ * @param value Value to check
936
+ * @returns `true` if the value is a plain object, otherwise `false`
937
+ */
938
+ function isPlainObject(value) {
939
+ if (value === null || typeof value !== "object") return false;
940
+ if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
941
+ const prototype = Object.getPrototypeOf(value);
942
+ return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
943
+ }
944
+ /**
945
+ * Is the value a typed array?
946
+ * @param value Value to check
947
+ * @returns `true` if the value is a typed array, otherwise `false`
948
+ */
949
+ function isTypedArray(value) {
950
+ TYPED_ARRAYS ??= new Set([
951
+ Int8Array,
952
+ Uint8Array,
953
+ Uint8ClampedArray,
954
+ Int16Array,
955
+ Uint16Array,
956
+ Int32Array,
957
+ Uint32Array,
958
+ Float32Array,
959
+ Float64Array,
960
+ BigInt64Array,
961
+ BigUint64Array
962
+ ]);
963
+ return TYPED_ARRAYS.has(value?.constructor);
964
+ }
965
+ let TYPED_ARRAYS;
966
+ //#endregion
891
967
  //#region node_modules/@oscarpalmer/atoms/dist/array/select.mjs
892
968
  function select(array, ...parameters) {
893
969
  return findValues("all", array, parameters, parameters.pop()).matched;
@@ -939,6 +1015,43 @@ const aggregators = {
939
1015
  sum: calculateSum
940
1016
  };
941
1017
  //#endregion
1018
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/string.mjs
1019
+ /**
1020
+ * Get the string value from any value
1021
+ * @param value Original value
1022
+ * @returns String representation of the value
1023
+ */
1024
+ function getString(value) {
1025
+ if (typeof value === "string") return value;
1026
+ if (value == null) return "";
1027
+ if (typeof value === "function") return getString(value());
1028
+ if (typeof value !== "object") return String(value);
1029
+ const asString = String(value.valueOf?.() ?? value);
1030
+ return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
1031
+ }
1032
+ function ignoreKey(key) {
1033
+ return EXPRESSION_IGNORED.test(key);
1034
+ }
1035
+ /**
1036
+ * Join an array of values into a string
1037
+ * @param value Array of values
1038
+ * @param delimiter Delimiter to use between values
1039
+ * @returns Joined string
1040
+ */
1041
+ function join(value, delimiter) {
1042
+ return compact(value).map(getString).join(typeof delimiter === "string" ? delimiter : "");
1043
+ }
1044
+ /**
1045
+ * Split a string into words _(and other readable parts)_
1046
+ * @param value Original string
1047
+ * @returns Array of words found in the string
1048
+ */
1049
+ function words(value) {
1050
+ return typeof value === "string" ? value.match(EXPRESSION_WORDS) ?? [] : [];
1051
+ }
1052
+ const EXPRESSION_IGNORED = /(^|\.)(__proto__|constructor|prototype)(\.|$)/i;
1053
+ const EXPRESSION_WORDS = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
1054
+ //#endregion
942
1055
  //#region node_modules/@oscarpalmer/atoms/dist/internal/value/handlers.mjs
943
1056
  function getCompareHandlers(owner, options) {
944
1057
  const { get, register, unregister } = getHandlers(owner, options);
@@ -1054,63 +1167,72 @@ const comparators$1 = {
1054
1167
  };
1055
1168
  //#endregion
1056
1169
  //#region node_modules/@oscarpalmer/atoms/dist/array/sort.mjs
1057
- function getCallback(value, key, forObject) {
1058
- if (key != null) return;
1059
- if (forObject && typeof value.value === "function") return value.value;
1060
- return typeof value === "function" ? value : void 0;
1061
- }
1062
- function getKey$1(value, forObject) {
1063
- if (forObject && typeof value.key === "string") return value.key;
1064
- return typeof value === "string" ? value : void 0;
1170
+ function getComparisonSorter(callback, modifier) {
1171
+ return {
1172
+ modifier,
1173
+ compare: { simple: callback },
1174
+ get: false,
1175
+ identifier: String(callback)
1176
+ };
1065
1177
  }
1066
- function getModifier(value, modifier, forObject) {
1067
- if (!forObject || typeof value.direction !== "string") return modifier;
1068
- if (value.direction === "ascending") return 1;
1069
- return value.direction === "descending" ? -1 : modifier;
1178
+ function getObjectSorter(obj, modifier) {
1179
+ let sorter;
1180
+ if (typeof obj.comparison === "function") sorter = getComparisonSorter(obj.comparison, modifier);
1181
+ else if (typeof obj.key === "string") {
1182
+ sorter = getValueSorter(obj.key, modifier);
1183
+ if (typeof obj.compare === "function") sorter.compare = { complex: obj.compare };
1184
+ } else if (typeof obj.value === "function") sorter = getValueSorter(obj.value, modifier);
1185
+ if (sorter != null && typeof obj.direction === "string") sorter.modifier = modifiers[obj.direction] ?? modifier;
1186
+ return sorter;
1070
1187
  }
1071
1188
  function getSorter(value, modifier) {
1072
- const forObject = isPlainObject(value);
1073
- const sorter = {
1074
- identifier: "",
1075
- modifier
1076
- };
1077
- sorter.compare = forObject && typeof value.compare === "function" ? value.compare : void 0;
1078
- sorter.key = getKey$1(value, forObject);
1079
- sorter.modifier = getModifier(value, modifier, forObject);
1080
- sorter.callback = getCallback(value, sorter.key, forObject);
1081
- if (sorter.key != null || sorter.callback != null) {
1082
- sorter.identifier = `${sorter.key ?? sorter.callback}`;
1083
- return sorter;
1189
+ switch (true) {
1190
+ case typeof value === "function": return getComparisonSorter(value, modifier);
1191
+ case typeof value === "string": return getValueSorter(value, modifier);
1192
+ case isPlainObject(value): return getObjectSorter(value, modifier);
1193
+ default: break;
1084
1194
  }
1085
1195
  }
1196
+ function getValueSorter(value, modifier) {
1197
+ return {
1198
+ modifier,
1199
+ get: true,
1200
+ identifier: String(value),
1201
+ value: typeof value === "function" ? value : (item) => item[value]
1202
+ };
1203
+ }
1086
1204
  function sort(array, first, second) {
1087
1205
  if (!Array.isArray(array)) return [];
1088
1206
  if (array.length < 2) return array;
1089
- const modifier = (first === true || second === true ? "descending" : "ascending") === "ascending" ? 1 : -1;
1207
+ const modifier = modifiers[first === true || second === true ? SORT_DIRECTION_DESCENDING : SORT_DIRECTION_ASCENDING];
1090
1208
  const sorters = (Array.isArray(first) ? first : [first]).map((item) => getSorter(item, modifier)).filter((sorter) => sorter != null).filter((current, index, filtered) => filtered.findIndex((next) => next.identifier === current.identifier) === index);
1091
1209
  const { length } = sorters;
1092
- if (length === 0) return array.sort((firstItem, secondItem) => compare(firstItem, secondItem) * modifier);
1210
+ if (length === 0) return array.sort((first, second) => compare(first, second) * modifier);
1093
1211
  if (length === 1) {
1094
1212
  const sorter = sorters[0];
1095
- const { callback, key } = sorter;
1096
1213
  return array.sort((firstItem, secondItem) => {
1097
- const firstValue = key == null ? callback?.(firstItem) : firstItem[key];
1098
- const secondValue = key == null ? callback?.(secondItem) : secondItem[key];
1099
- return (sorter.compare?.(firstItem, firstValue, secondItem, secondValue) ?? compare(firstValue, secondValue)) * sorter.modifier;
1214
+ const firstValue = sorter.get ? sorter.value(firstItem) : firstItem;
1215
+ const secondValue = sorter.get ? sorter.value(secondItem) : secondItem;
1216
+ return (sorter.compare?.complex?.(firstItem, firstValue, secondItem, secondValue) ?? sorter.compare?.simple?.(firstItem, secondItem) ?? compare(firstValue, secondValue)) * sorter.modifier;
1100
1217
  });
1101
1218
  }
1102
1219
  return array.sort((firstItem, secondItem) => {
1103
1220
  for (let index = 0; index < length; index += 1) {
1104
1221
  const sorter = sorters[index];
1105
- const { callback, key } = sorter;
1106
- const firstValue = key == null ? callback?.(firstItem) : firstItem[key];
1107
- const secondValue = key == null ? callback?.(secondItem) : secondItem[key];
1108
- const compared = (sorter.compare?.(firstItem, firstValue, secondItem, secondValue) ?? compare(firstValue, secondValue)) * sorter.modifier;
1109
- if (compared !== 0) return compared;
1222
+ const firstValue = sorter.value?.(firstItem) ?? firstItem;
1223
+ const secondValue = sorter.value?.(secondItem) ?? secondItem;
1224
+ const comparison = (sorter.compare?.complex?.(firstItem, firstValue, secondItem, secondValue) ?? sorter.compare?.simple?.(firstItem, secondItem) ?? compare(firstValue, secondValue)) * sorter.modifier;
1225
+ if (comparison !== 0) return comparison;
1110
1226
  }
1111
1227
  return 0;
1112
1228
  });
1113
1229
  }
1230
+ const SORT_DIRECTION_ASCENDING = "ascending";
1231
+ const SORT_DIRECTION_DESCENDING = "descending";
1232
+ const modifiers = {
1233
+ [SORT_DIRECTION_ASCENDING]: 1,
1234
+ [SORT_DIRECTION_DESCENDING]: -1
1235
+ };
1114
1236
  //#endregion
1115
1237
  //#region node_modules/@oscarpalmer/atoms/dist/array/to-map.mjs
1116
1238
  function getMapValues(array, first, second, arrays) {
@@ -1166,6 +1288,17 @@ function toRecordArrays(array, first, second) {
1166
1288
  return groupValues(array, first, second, true);
1167
1289
  }
1168
1290
  //#endregion
1291
+ //#region node_modules/@oscarpalmer/atoms/dist/is.mjs
1292
+ /**
1293
+ * Is the value `undefined`, `null`, or a whitespace-only string?
1294
+ * @param value Value to check
1295
+ * @returns `true` if the value is nullable or a whitespace-only string, otherwise `false`
1296
+ */
1297
+ function isNullableOrWhitespace(value) {
1298
+ return value == null || EXPRESSION_WHITESPACE.test(getString(value));
1299
+ }
1300
+ const EXPRESSION_WHITESPACE = /^\s*$/;
1301
+ //#endregion
1169
1302
  //#region node_modules/@oscarpalmer/atoms/dist/internal/function/timer.mjs
1170
1303
  function getInterval(value) {
1171
1304
  return typeof value === "number" && value > 0 ? value : 0;
@@ -1310,6 +1443,10 @@ function getWithHasValue(data, path, ignoreCase) {
1310
1443
  return getNestedValue(data, path, ignoreCase === true);
1311
1444
  }
1312
1445
  //#endregion
1446
+ //#region src/models/group.model.ts
1447
+ const GROUP_KEY_EXPRESSION = /^group:(.+)$/;
1448
+ const GROUP_KEY_PREFIX = "group:";
1449
+ //#endregion
1313
1450
  //#region src/components/group.component.ts
1314
1451
  var GroupComponent = class {
1315
1452
  element;
@@ -1322,7 +1459,7 @@ var GroupComponent = class {
1322
1459
  constructor(label, value) {
1323
1460
  this.label = label;
1324
1461
  const stringified = getString(value);
1325
- this.key = `group:${stringified}`;
1462
+ this.key = `${GROUP_KEY_PREFIX}${stringified}`;
1326
1463
  this.value = {
1327
1464
  stringified,
1328
1465
  original: value
@@ -1336,86 +1473,126 @@ function removeGroup(group) {
1336
1473
  }
1337
1474
  function renderGroup(state, component) {
1338
1475
  component.element ??= createElement("div", {
1339
- className: `${CSS_TABELA_ROW} ${CSS_TABELA_ROW_GROUP}`,
1340
- innerHTML: `<div class="tabela__cell tabela__cell--group" role="cell">
1341
- <button class="tabela__button tabela__button--group" data-event="group" data-key="tabela_${state.id}_${component.key}" type="button">
1476
+ className: `${CSS_ROW} ${CSS_ROW_GROUP}`,
1477
+ innerHTML: `<div class="${CSS_CELL} ${CSS_CELL_GROUP}" role="${ROLE_CELL}">
1478
+ <button class="${CSS_BUTTON} ${CSS_BUTTON_GROUP}" ${ATTRIBUTE_DATA_EVENT}="${EVENT_GROUP}" ${ATTRIBUTE_DATA_KEY}="${state.prefix}_${component.key}" type="button">
1342
1479
  <span aria-hidden="true"></span>
1343
1480
  <span>Open/close</span>
1344
1481
  </button>
1345
1482
  <p>${component.label}</p>
1346
- <span class="tabela__group__total">${component.total}</span>
1347
- <span class="tabela__group__selected">${component.selected === 0 ? "" : component.selected}</span>
1483
+ <span class="${CSS_GROUP_TOTAL}">${component.total}</span>
1484
+ <span class="${CSS_GROUP_SELECTED}">${component.selected === 0 ? "" : component.selected}</span>
1348
1485
  </div>`,
1349
- role: "row"
1486
+ [ATTRIBUTE_ROLE]: "row"
1350
1487
  }, {}, { height: `${state.options.rowHeight}px` });
1351
1488
  }
1352
- function updateGroup(state, component) {
1489
+ function updateGroup(state, component, emit) {
1353
1490
  if (component.element == null) return;
1354
- const selected = component.element.querySelector(".tabela__group__selected");
1355
- const total = component.element.querySelector(".tabela__group__total");
1491
+ const selected = component.element.querySelector(selectedSelector);
1492
+ const total = component.element.querySelector(totalSelector);
1356
1493
  if (selected != null) selected.textContent = component.selected === 0 ? "" : String(component.selected);
1357
1494
  if (total != null) total.textContent = String(component.total);
1495
+ if (emit) state.managers.event.emit(EVENT_GROUP_UPDATE, [component]);
1358
1496
  }
1497
+ const selectedSelector = `.${CSS_GROUP_SELECTED}`;
1498
+ const totalSelector = `.${CSS_GROUP_TOTAL}`;
1359
1499
  //#endregion
1360
- //#region src/managers/sort.manager.ts
1361
- var SortManager = class {
1362
- handlers = Object.freeze({
1363
- add: (field, direction) => this.add(field, direction),
1364
- flip: (field) => this.flip(field),
1365
- clear: () => this.clear(),
1366
- remove: (field) => this.remove(field),
1367
- set: (items) => this.set(items)
1368
- });
1500
+ //#region src/helpers/misc.helpers.ts
1501
+ function getGroup(group) {
1502
+ return { value: group.value.original };
1503
+ }
1504
+ function getKey(value) {
1505
+ if (typeof value === "number") return value;
1506
+ if (typeof value !== "string") return;
1507
+ return integerExpression.test(value) ? Number.parseInt(value, 10) : value;
1508
+ }
1509
+ function isEvent(value) {
1510
+ return EVENTS_NAMES.has(value);
1511
+ }
1512
+ function isGroupKey(key) {
1513
+ return typeof key === "string" && GROUP_KEY_EXPRESSION.test(key);
1514
+ }
1515
+ const integerExpression = /^\d+$/;
1516
+ //#endregion
1517
+ //#region src/models/sort.model.ts
1518
+ const SORT_ASCENDING = "ascending";
1519
+ const SORT_DESCENDING = "descending";
1520
+ //#endregion
1521
+ //#region src/managers/sort.manager.ts
1522
+ var SortManager = class {
1523
+ handlers = {
1524
+ add: (field, direction) => this.add(field, direction),
1525
+ flip: (field) => this.flip(field),
1526
+ clear: () => this.clear(),
1527
+ remove: (field) => this.remove(field),
1528
+ set: (items) => this.set(items, true)
1529
+ };
1369
1530
  items = [];
1370
1531
  constructor(state) {
1371
1532
  this.state = state;
1372
1533
  }
1373
- add(field, direction) {
1374
- if (this.items.findIndex((item) => item.key === field) > -1) return;
1534
+ add(key, direction) {
1535
+ if (this.items.findIndex((item) => item.key === key) > -1) return;
1375
1536
  this.items.push({
1376
- key: field,
1537
+ key,
1377
1538
  direction: direction ?? "ascending"
1378
1539
  });
1540
+ this.state.managers.event.emit(EVENT_SORT_ADD, [{
1541
+ key,
1542
+ direction: direction ?? "ascending"
1543
+ }]);
1379
1544
  this.sort();
1380
1545
  }
1381
- addOrSet(event, field) {
1382
- if (event.ctrlKey || event.metaKey) this.add(field);
1546
+ addOrSet(event, key) {
1547
+ if (event.ctrlKey || event.metaKey) this.add(key);
1383
1548
  else this.set([{
1384
- field,
1385
- direction: "ascending"
1386
- }]);
1549
+ key,
1550
+ direction: SORT_ASCENDING
1551
+ }], false);
1387
1552
  }
1388
1553
  clear() {
1389
- if (this.items.length > 0) {
1390
- this.items.length = 0;
1391
- this.sort();
1392
- }
1554
+ if (this.items.length === 0) return;
1555
+ this.items.length = 0;
1556
+ this.state.managers.event.emit(EVENT_SORT_CLEAR);
1557
+ this.sort();
1393
1558
  }
1394
1559
  destroy() {
1395
1560
  this.handlers = void 0;
1396
1561
  this.items = void 0;
1397
1562
  this.state = void 0;
1398
1563
  }
1399
- flip(field) {
1400
- const item = this.items.find((item) => item.key === field);
1564
+ flip(key) {
1565
+ const item = this.items.find((item) => item.key === key);
1401
1566
  if (item == null) return;
1402
- item.direction = item.direction === "ascending" ? "descending" : "ascending";
1567
+ item.direction = item.direction === "ascending" ? SORT_DESCENDING : SORT_ASCENDING;
1568
+ this.state.managers.event.emit(EVENT_SORT_FLIP, [{
1569
+ key,
1570
+ direction: item.direction
1571
+ }]);
1403
1572
  this.sort();
1404
1573
  }
1405
- remove(field) {
1406
- const index = this.items.findIndex((item) => item.key === field);
1407
- if (index > -1) {
1408
- this.items.splice(index, 1);
1409
- this.sort();
1410
- }
1411
- }
1412
- removeOrClear(event, field) {
1413
- if (event.ctrlKey || event.metaKey) this.remove(field);
1414
- else this.clear();
1574
+ remove(key) {
1575
+ const index = this.items.findIndex((item) => item.key === key);
1576
+ if (index === -1) return;
1577
+ const spliced = this.items.splice(index, 1);
1578
+ this.state.managers.event.emit(EVENT_SORT_REMOVE, spliced);
1579
+ if (this.items.length === 0) this.state.managers.event.emit(EVENT_SORT_CLEAR);
1580
+ this.sort();
1415
1581
  }
1416
- set(items) {
1417
- this.items.splice(0, this.items.length, ...items.map((item) => ({
1418
- key: item.field,
1582
+ set(items, set) {
1583
+ const removed = this.items.splice(0, this.items.length, ...items.map((item) => ({
1584
+ key: item.key,
1585
+ direction: item.direction
1586
+ })));
1587
+ if (set) this.state.managers.event.emit(EVENT_SORT_SET, {
1588
+ removed,
1589
+ added: items.map((item) => ({
1590
+ key: item.key,
1591
+ direction: item.direction
1592
+ }))
1593
+ });
1594
+ else this.state.managers.event.emit(EVENT_SORT_ADD, items.map((item) => ({
1595
+ key: item.key,
1419
1596
  direction: item.direction
1420
1597
  })));
1421
1598
  this.sort();
@@ -1425,47 +1602,48 @@ var SortManager = class {
1425
1602
  const { length } = state.managers.column.items;
1426
1603
  for (let index = 0; index < length; index += 1) {
1427
1604
  const column = state.managers.column.items[index];
1428
- const sorterIndex = items.findIndex((item) => item.key === column.options.field);
1605
+ const sorterIndex = items.findIndex((item) => item.key === column.options.key);
1429
1606
  const sorterItem = items[sorterIndex];
1430
1607
  setAttributes(column.elements.wrapper, {
1431
- "aria-sort": sorterItem == null ? "none" : items.length > 1 ? "other" : sorterItem.direction,
1432
- "data-sort-direction": sorterItem == null ? void 0 : sorterItem.direction
1608
+ [ARIA_SORT]: sorterItem == null ? SORT_NONE : items.length > 1 ? SORT_OTHER : sorterItem.direction,
1609
+ [ATTRIBUTE_DATA_SORT_DIRECTION]: sorterItem == null ? void 0 : sorterItem.direction
1433
1610
  });
1434
- setAttribute(column.elements.sorter, "data-sort-position", sorterIndex > -1 && items.length > 1 ? sorterIndex + 1 : void 0);
1611
+ setAttribute(column.elements.sorter, ATTRIBUTE_DATA_SORT_POSITION, sorterIndex > -1 && items.length > 1 ? sorterIndex + 1 : void 0);
1435
1612
  }
1436
- state.managers.data.state.items.active = items.length === 0 ? void 0 : getSortedItems(state, items);
1613
+ state.managers.data.state.keys.active = items.length === 0 ? void 0 : getSortedItems(state, items);
1614
+ state.managers.event.emit(EVENT_DATA_SORTED, state.managers.data.get(true));
1437
1615
  state.managers.render.update(true, true);
1438
1616
  }
1439
- toggle(event, field, direction) {
1617
+ toggle(event, key, direction) {
1440
1618
  switch (direction) {
1441
- case "ascending":
1442
- this.flip(field);
1619
+ case SORT_ASCENDING:
1620
+ this.flip(key);
1443
1621
  return;
1444
- case "descending":
1445
- this.removeOrClear(event, field);
1622
+ case SORT_DESCENDING:
1623
+ this.remove(key);
1446
1624
  return;
1447
1625
  default:
1448
- this.addOrSet(event, field);
1626
+ this.addOrSet(event, key);
1449
1627
  return;
1450
1628
  }
1451
1629
  }
1452
1630
  };
1453
1631
  function getSortedItems(state, sorters) {
1454
- const data = state.managers.data.state.items.active?.map((key) => key instanceof GroupComponent ? key : state.managers.data.state.values.mapped.get(key)) ?? state.managers.data.state.values.array.slice();
1632
+ const data = state.managers.data.state.keys.active?.map((key) => isGroupKey(key) ? key : state.managers.data.state.values.mapped.get(key)) ?? state.managers.data.state.values.array;
1455
1633
  if (!state.managers.group.enabled) return sort(data, sorters).map((item) => getValue(item, state.key));
1456
- return sortWithGroups(state, data, sorters).map((item) => item instanceof GroupComponent ? item : getValue(item, state.key));
1634
+ return sortWithGroups(state, data, sorters).map((item) => isGroupKey(item) ? item : getValue(item, state.key));
1457
1635
  }
1458
1636
  function sortWithGroups(state, data, sorters) {
1459
1637
  const { length } = sorters;
1460
1638
  return data.sort((first, second) => {
1461
- const firstValue = first instanceof GroupComponent ? first.value.stringified : getValue(first, state.managers.group.field);
1462
- const secondValue = second instanceof GroupComponent ? second.value.stringified : getValue(second, state.managers.group.field);
1639
+ const firstIsGroup = isGroupKey(first);
1640
+ const secondIsGroup = isGroupKey(second);
1641
+ const firstValue = firstIsGroup ? state.managers.group.getForKey(first).value.stringified : getValue(first, state.managers.group.key);
1642
+ const secondValue = secondIsGroup ? state.managers.group.getForKey(second).value.stringified : getValue(second, state.managers.group.key);
1463
1643
  const firstOrder = state.managers.group.order[firstValue];
1464
1644
  const secondOrder = state.managers.group.order[secondValue];
1465
1645
  const groupComparison = compare(firstOrder, secondOrder);
1466
1646
  if (groupComparison !== 0) return groupComparison;
1467
- const firstIsGroup = first instanceof GroupComponent;
1468
- const secondIsGroup = second instanceof GroupComponent;
1469
1647
  if (firstIsGroup || secondIsGroup) return firstIsGroup && secondIsGroup ? 0 : firstIsGroup ? -1 : 1;
1470
1648
  for (let index = 0; index < length; index += 1) {
1471
1649
  const sorter = sorters[index];
@@ -1475,28 +1653,30 @@ function sortWithGroups(state, data, sorters) {
1475
1653
  return 0;
1476
1654
  });
1477
1655
  }
1656
+ const SORT_NONE = "none";
1657
+ const SORT_OTHER = "other";
1478
1658
  //#endregion
1479
1659
  //#region src/managers/data.manager.ts
1480
1660
  var DataManager = class {
1481
- handlers = Object.freeze({
1482
- add: (data) => void this.add(data, true),
1483
- clear: () => void this.clear(),
1661
+ handlers = {
1662
+ add: (data) => this.add(data, true),
1663
+ clear: () => this.clear(),
1484
1664
  get: (active) => this.get(active),
1485
- remove: (items) => void this.remove(items, true),
1486
- synchronize: (data, remove) => void this.synchronize(data, remove),
1487
- update: (data) => void this.update(data)
1488
- });
1665
+ remove: (items) => this.remove(items, true),
1666
+ synchronize: (data, remove) => this.synchronize(data, remove === true),
1667
+ update: (data) => this.update(data, true)
1668
+ };
1489
1669
  state;
1490
- get items() {
1491
- return this.state.items.active ?? this.state.items.original;
1670
+ get keys() {
1671
+ return this.state.keys.active ?? this.state.keys.original;
1492
1672
  }
1493
1673
  get size() {
1494
- return this.items.length;
1674
+ return this.keys.length;
1495
1675
  }
1496
1676
  constructor(state) {
1497
1677
  this.state = {
1498
1678
  ...state,
1499
- items: { original: [] },
1679
+ keys: { original: [] },
1500
1680
  values: {
1501
1681
  array: [],
1502
1682
  mapped: /* @__PURE__ */ new Map()
@@ -1505,125 +1685,151 @@ var DataManager = class {
1505
1685
  }
1506
1686
  async add(data, render) {
1507
1687
  const { state } = this;
1508
- const groups = [];
1509
- const updates = [];
1688
+ const addedData = [];
1689
+ const updatedData = [];
1690
+ const addedGroups = [];
1691
+ const updatedGroups = [];
1510
1692
  let groupColumn;
1511
1693
  let { length } = data;
1512
1694
  for (let index = 0; index < length; index += 1) {
1513
1695
  const item = data[index];
1514
1696
  const key = getValue(item, state.key);
1515
1697
  if (state.values.mapped.has(key)) {
1516
- updates.push(item);
1698
+ updatedData.push(item);
1517
1699
  continue;
1518
1700
  }
1701
+ addedData.push(item);
1519
1702
  state.values.array.push(item);
1520
1703
  state.values.mapped.set(key, item);
1521
1704
  if (!state.managers.group.enabled) continue;
1522
- const groupValue = getValue(item, state.managers.group.field);
1523
- let group = state.managers.group.get(groupValue);
1705
+ const groupValue = getValue(item, state.managers.group.key);
1706
+ let group = state.managers.group.getForValue(groupValue);
1524
1707
  if (group == null) {
1525
- groupColumn ??= state.managers.column.get(state.managers.group.field);
1526
- group = new GroupComponent(`${groupColumn?.options.title ?? state.managers.group.field}: ${groupValue}`, groupValue);
1527
- state.values.array.push(group);
1528
- state.managers.group.add(group);
1529
- }
1708
+ groupColumn ??= state.managers.column.get(state.managers.group.key);
1709
+ group = new GroupComponent(`${groupColumn?.options.label ?? state.managers.group.key}: ${groupValue}`, groupValue);
1710
+ state.values.array.push(group.key);
1711
+ state.managers.group.add(group, false);
1712
+ addedGroups.push(group);
1713
+ } else if (!addedGroups.includes(group) && !updatedGroups.includes(group)) updatedGroups.push(group);
1530
1714
  if (!group.expanded) state.managers.group.collapsed.add(key);
1531
1715
  group.total += 1;
1532
- groups.push(group);
1533
1716
  }
1534
- length = groups.length;
1535
- for (let index = 0; index < length; index += 1) updateGroup(state, groups[index]);
1536
- if (updates.length > 0) this.update(updates);
1537
- else if (render) this.render();
1717
+ length = addedGroups.length;
1718
+ if (length > 0) {
1719
+ state.managers.event.emit(EVENT_GROUP_ADD, addedGroups.map(getGroup));
1720
+ for (let index = 0; index < length; index += 1) updateGroup(state, addedGroups[index], false);
1721
+ }
1722
+ length = updatedGroups.length;
1723
+ if (length > 0) {
1724
+ for (let index = 0; index < length; index += 1) updateGroup(state, updatedGroups[index], false);
1725
+ state.managers.event.emit(EVENT_GROUP_UPDATE, updatedGroups.map(getGroup));
1726
+ }
1727
+ await this.update(updatedData, addedData.length === 0);
1728
+ if (addedData.length === 0) return;
1729
+ state.managers.event.emit(EVENT_DATA_ADD, addedData);
1730
+ if (render) this.render();
1538
1731
  }
1539
- clear() {
1540
- if (this.state.values.array.length > 0) this.removeItems([], true, true);
1732
+ async clear() {
1733
+ if (this.state.values.array.length > 0) return this.removeItems([], true, true).then(() => void 0);
1541
1734
  }
1542
1735
  destroy() {
1543
1736
  const { state } = this;
1544
1737
  state.values.mapped.clear();
1545
- state.items.active = void 0;
1546
- state.items.original.length = 0;
1738
+ state.keys.active = void 0;
1739
+ state.keys.original.length = 0;
1547
1740
  state.values.array.length = 0;
1548
1741
  this.handlers = void 0;
1549
1742
  this.state = void 0;
1550
1743
  }
1551
1744
  get(active) {
1552
1745
  const { state } = this;
1553
- return active ?? false ? select(state.items.active ?? [], (key) => !(key instanceof GroupComponent), (key) => state.values.mapped.get(key)) : state.values.array.filter((item) => !(item instanceof GroupComponent));
1746
+ return (active ?? false) && state.keys.active != null ? select(state.keys.active, (key) => !isGroupKey(key), (key) => state.values.mapped.get(key)) : state.values.array.filter((item) => !isGroupKey(item));
1554
1747
  }
1555
1748
  getIndex(item) {
1556
- if (item instanceof GroupComponent) return this.items.indexOf(item);
1557
- return this.items.findIndex((value) => value instanceof GroupComponent ? value.key === item : value === item);
1749
+ return this.keys.indexOf(item);
1558
1750
  }
1559
1751
  async remove(items, render) {
1560
1752
  const { state } = this;
1561
- const keys = items.map((value) => isPlainObject(value) ? getValue(value, state.key) : value);
1753
+ const keys = items.map((value) => isPlainObject(value) ? getValue(value, state.key) : value).filter((key) => !isGroupKey(key));
1562
1754
  const { length } = keys;
1563
- if (length > 0) return this.removeItems(keys, false, render === true);
1755
+ return length === 0 ? render ? void 0 : [] : this.removeItems(keys, false, render);
1564
1756
  }
1565
- async removeItems(items, clear, render) {
1757
+ async removeItems(keys, clear, render) {
1566
1758
  const { state } = this;
1567
1759
  if (clear) {
1568
- state.items.active = void 0;
1569
- state.items.original = [];
1760
+ state.keys.active = void 0;
1761
+ state.keys.original = [];
1570
1762
  state.values.array = [];
1571
1763
  state.values.mapped.clear();
1572
1764
  state.managers.row.clear();
1573
1765
  if (state.managers.group.enabled) state.managers.group.clear();
1574
- return this.render();
1766
+ state.managers.event.emit(EVENT_DATA_CLEAR);
1767
+ this.render();
1768
+ return render ? void 0 : [];
1575
1769
  }
1576
- const groups = [];
1577
- const chunked = chunk(items);
1770
+ const removedGroups = [];
1771
+ const updatedGroups = [];
1772
+ const removedData = [];
1773
+ const chunked = chunk(keys);
1578
1774
  const chunkedLength = chunked.length;
1579
1775
  for (let chunkedIndex = 0; chunkedIndex < chunkedLength; chunkedIndex += 1) {
1580
1776
  const chunk = chunked[chunkedIndex];
1581
1777
  const chunkLength = chunk.length;
1582
- for (let itemIndex = 0; itemIndex < chunkLength; itemIndex += 1) {
1583
- const item = chunk[itemIndex];
1584
- const dataIndex = state.items.original.indexOf(item);
1778
+ for (let keyIndex = 0; keyIndex < chunkLength; keyIndex += 1) {
1779
+ const key = chunk[keyIndex];
1780
+ const dataIndex = state.keys.original.indexOf(key);
1585
1781
  let dataValue;
1586
1782
  [dataValue] = state.values.array.splice(dataIndex, 1);
1587
- state.items.original.splice(dataIndex, 1);
1588
- state.managers.row.remove(item);
1589
- state.values.mapped.delete(item);
1590
- if (!state.managers.group.enabled || item instanceof GroupComponent) continue;
1591
- state.managers.group.collapsed.delete(item);
1592
- const groupKey = getValue(dataValue, state.managers.group.field);
1593
- const group = state.managers.group.get(groupKey);
1783
+ removedData.push(dataValue);
1784
+ state.keys.original.splice(dataIndex, 1);
1785
+ state.managers.row.remove(key);
1786
+ state.values.mapped.delete(key);
1787
+ if (!state.managers.group.enabled || isGroupKey(key)) continue;
1788
+ state.managers.group.collapsed.delete(key);
1789
+ const groupValue = getValue(dataValue, state.managers.group.key);
1790
+ const group = state.managers.group.getForValue(groupValue);
1594
1791
  if (group == null) continue;
1595
1792
  group.total -= 1;
1596
1793
  if (group.total > 0) {
1597
- groups.push(group);
1794
+ updatedGroups.push(group);
1598
1795
  continue;
1599
1796
  }
1600
- let groupIndex = groups.indexOf(group);
1601
- if (groupIndex > -1) groups.splice(groupIndex, 1);
1602
- groupIndex = state.values.array.indexOf(group);
1797
+ let groupIndex = updatedGroups.indexOf(group);
1798
+ if (groupIndex > -1) updatedGroups.splice(groupIndex, 1);
1799
+ groupIndex = state.values.array.indexOf(group.key);
1603
1800
  if (groupIndex > -1) {
1604
- state.items.original.splice(groupIndex, 1);
1801
+ state.keys.original.splice(groupIndex, 1);
1605
1802
  state.values.array.splice(groupIndex, 1);
1606
1803
  }
1607
- state.managers.group.remove(group);
1608
- if (items.length >= 1e4) await delay(25);
1804
+ removedGroups.push(group);
1805
+ state.managers.group.remove(group, false);
1806
+ if (keys.length >= 1e4) await delay(25);
1609
1807
  }
1610
1808
  }
1611
- const { length } = groups;
1612
- for (let index = 0; index < length; index += 1) updateGroup(state, groups[index]);
1613
- if (render) return this.render();
1809
+ let { length } = updatedGroups;
1810
+ if (length > 0) {
1811
+ for (let index = 0; index < length; index += 1) updateGroup(state, updatedGroups[index], false);
1812
+ state.managers.event.emit(EVENT_GROUP_UPDATE, updatedGroups.map(getGroup));
1813
+ }
1814
+ length = removedGroups.length;
1815
+ if (length > 0) state.managers.event.emit(EVENT_GROUP_REMOVE, removedGroups.map(getGroup));
1816
+ state.managers.event.emit(EVENT_DATA_REMOVE, removedData);
1817
+ if (render) this.render();
1818
+ return render ? void 0 : removedData;
1614
1819
  }
1615
1820
  render() {
1616
1821
  const { state } = this;
1617
1822
  if (state.managers.group.enabled) sortWithGroups(state, state.values.array, [{
1618
- direction: "ascending",
1823
+ direction: SORT_ASCENDING,
1619
1824
  key: state.key
1620
1825
  }]);
1621
1826
  else sort(state.values.array, [{
1622
- direction: "ascending",
1827
+ direction: SORT_ASCENDING,
1623
1828
  key: state.key
1624
1829
  }]);
1625
- state.items.original = state.values.array.map((item) => item instanceof GroupComponent ? item : getValue(item, state.key));
1626
- state.values.mapped = toMap(state.values.array.filter((item) => !(item instanceof GroupComponent)), (item) => getValue(item, state.key));
1830
+ state.keys.active = void 0;
1831
+ state.keys.original = state.values.array.map((item) => typeof item === "string" ? item : getValue(item, state.key));
1832
+ state.values.mapped = toMap(state.values.array.filter((item) => !isGroupKey(item)), (item) => getValue(item, state.key));
1627
1833
  if (Object.keys(state.managers.filter.items).length > 0) state.managers.filter.filter();
1628
1834
  else if (state.managers.sort.items.length > 0) state.managers.sort.sort();
1629
1835
  else state.managers.render.update(true, true);
@@ -1632,17 +1838,17 @@ var DataManager = class {
1632
1838
  const { state } = this;
1633
1839
  const array = data.slice();
1634
1840
  if (state.managers.group.enabled) {
1635
- const column = state.managers.column.get(state.managers.group.field);
1636
- const grouped = toRecord.arrays(data, state.managers.group.field);
1841
+ const column = state.managers.column.get(state.managers.group.key);
1842
+ const grouped = toRecord.arrays(data, state.managers.group.key);
1637
1843
  const entries = Object.entries(grouped);
1638
1844
  const { length } = entries;
1639
1845
  const groups = [];
1640
1846
  for (let index = 0; index < length; index += 1) {
1641
1847
  const [value, items] = entries[index];
1642
- const group = new GroupComponent(`${column?.options.title ?? state.managers.group.field}: ${value}`, value);
1848
+ const group = new GroupComponent(`${column?.options.label ?? state.managers.group.key}: ${value}`, value);
1643
1849
  group.total = items.length;
1644
1850
  groups.push(group);
1645
- array.push(group);
1851
+ array.push(group.key);
1646
1852
  }
1647
1853
  state.managers.group.set(groups);
1648
1854
  }
@@ -1651,7 +1857,7 @@ var DataManager = class {
1651
1857
  }
1652
1858
  async synchronize(data, remove) {
1653
1859
  const { state } = this;
1654
- const add = [];
1860
+ const added = [];
1655
1861
  const updated = [];
1656
1862
  const keys = /* @__PURE__ */ new Set([]);
1657
1863
  const { length } = data;
@@ -1659,33 +1865,38 @@ var DataManager = class {
1659
1865
  const object = data[index];
1660
1866
  const key = getValue(object, state.key);
1661
1867
  if (state.values.mapped.has(key)) updated.push(object);
1662
- else add.push(object);
1868
+ else added.push(object);
1663
1869
  keys.add(key);
1664
1870
  }
1665
1871
  if (keys.size === 0) return;
1666
- if (remove ?? false) {
1667
- const toRemove = state.items.original.filter((key) => !(key instanceof GroupComponent) && !keys.has(key));
1668
- if (toRemove.length > 0) await this.remove(toRemove, false);
1872
+ let removed = [];
1873
+ if (remove) {
1874
+ const toRemove = state.keys.original.filter((key) => !isGroupKey(key) && !keys.has(key));
1875
+ if (toRemove.length > 0) removed = await this.remove(toRemove, false);
1669
1876
  }
1670
- await this.update(updated);
1671
- if (add.length > 0) await this.add(add, false);
1672
- if (add.length > 0 || (remove ?? false)) this.render();
1877
+ await this.update(updated, added.length === 0);
1878
+ await this.add(added, false);
1879
+ state.managers.event.emit(EVENT_DATA_SYNCHRONIZE, {
1880
+ added,
1881
+ removed,
1882
+ updated
1883
+ });
1884
+ if (added.length > 0 || remove) this.render();
1673
1885
  }
1674
- async update(data) {
1886
+ async update(data, render) {
1675
1887
  const { state } = this;
1676
1888
  const { length } = data;
1889
+ const updated = [];
1677
1890
  for (let index = 0; index < length; index += 1) {
1678
- const object = data[index];
1679
- const key = getValue(object, state.key);
1680
- const value = state.values.mapped.get(key);
1681
- if (value != null) {
1682
- state.values.mapped.set(key, {
1683
- ...value,
1684
- ...object
1685
- });
1686
- state.managers.row.update(key);
1687
- }
1891
+ const item = data[index];
1892
+ const key = getValue(item, state.key);
1893
+ const existing = state.keys.original.indexOf(key);
1894
+ if (existing === -1) continue;
1895
+ Object.assign(state.values.array[existing], item);
1896
+ updated.push(state.values.array[existing]);
1897
+ if (render && state.managers.render.visible.keys.has(key)) state.managers.row.update(key);
1688
1898
  }
1899
+ if (updated.length > 0) state.managers.event.emit(EVENT_DATA_UPDATE, updated);
1689
1900
  }
1690
1901
  };
1691
1902
  //#endregion
@@ -1772,7 +1983,7 @@ const EVENT_TYPES = new Set([
1772
1983
  const HANDLER_ACTIVE = delegatedEventHandler.bind(false);
1773
1984
  const HANDLER_PASSIVE = delegatedEventHandler.bind(true);
1774
1985
  //#endregion
1775
- //#region node_modules/@oscarpalmer/atoms/dist/internal/function/misc.mjs
1986
+ //#region node_modules/@oscarpalmer/toretto/node_modules/@oscarpalmer/atoms/dist/internal/function/misc.mjs
1776
1987
  /**
1777
1988
  * A function that does nothing, which can be useful, I guess…
1778
1989
  */
@@ -1843,31 +2054,50 @@ function getElement(origin) {
1843
2054
  //#endregion
1844
2055
  //#region src/managers/event.manager.ts
1845
2056
  var EventManager = class {
2057
+ events = {};
2058
+ handlers = {
2059
+ subscribe: (name, callback) => this.subscribe(name, callback),
2060
+ unsubscribe: (name, callback) => this.unsubscribe(name, callback)
2061
+ };
1846
2062
  constructor(state) {
1847
2063
  this.state = state;
1848
2064
  mapped$1.set(state.element, this);
1849
2065
  }
2066
+ emit(name, ...parameters) {
2067
+ if (this.events[name] == null) return;
2068
+ const handlers = [...this.events[name]];
2069
+ const { length } = handlers;
2070
+ for (let index = 0; index < length; index += 1) handlers[index](...parameters);
2071
+ }
1850
2072
  destroy() {
1851
2073
  mapped$1.delete(this.state.element);
1852
2074
  this.state = void 0;
1853
2075
  }
1854
2076
  onSort(event, target) {
1855
- const direction = target.getAttribute("data-sort-direction");
1856
- const field = target.getAttribute("data-field");
1857
- if (field != null) this.state.managers.sort.toggle(event, field, direction);
2077
+ const direction = target.getAttribute(ATTRIBUTE_DATA_SORT_DIRECTION);
2078
+ const key = target.getAttribute(ATTRIBUTE_DATA_KEY);
2079
+ if (key != null) this.state.managers.sort.toggle(event, key, direction);
2080
+ }
2081
+ subscribe(name, callback) {
2082
+ if (!isEvent(name) || typeof callback !== "function") return;
2083
+ this.events[name] ??= /* @__PURE__ */ new Set();
2084
+ this.events[name].add(callback);
2085
+ }
2086
+ unsubscribe(name, callback) {
2087
+ if (isEvent(name) && typeof callback === "function") this.events[name]?.delete(callback);
1858
2088
  }
1859
2089
  };
1860
2090
  function onClick(event) {
1861
- const target = findAncestor(event, "[data-event]");
1862
- const table = findAncestor(event, ".tabela__table");
2091
+ const target = findAncestor(event, eventAttribute);
2092
+ const table = findAncestor(event, tableClassName);
1863
2093
  if (!(target instanceof HTMLElement) || !(table instanceof HTMLElement)) return;
1864
2094
  const manager = mapped$1.get(table);
1865
2095
  if (manager == null) return;
1866
- switch (target?.getAttribute("data-event")) {
1867
- case "group":
2096
+ switch (target?.getAttribute(ATTRIBUTE_DATA_EVENT)) {
2097
+ case EVENT_GROUP:
1868
2098
  manager.state.managers.group.handle(target);
1869
2099
  break;
1870
- case "heading":
2100
+ case EVENT_HEADING:
1871
2101
  manager.onSort(event, target);
1872
2102
  break;
1873
2103
  case "row":
@@ -1877,8 +2107,8 @@ function onClick(event) {
1877
2107
  }
1878
2108
  }
1879
2109
  function onKeydown(event) {
1880
- const target = findAncestor(event, "[data-event]");
1881
- const table = findAncestor(event, ".tabela__table");
2110
+ const target = findAncestor(event, eventAttribute);
2111
+ const table = findAncestor(event, tableClassName);
1882
2112
  if (!(target instanceof HTMLElement) || !(table instanceof HTMLElement)) return;
1883
2113
  const manager = mapped$1.get(table);
1884
2114
  if (manager == null) return;
@@ -1888,10 +2118,211 @@ function onKeydown(event) {
1888
2118
  }
1889
2119
  manager.state.managers.navigation.handle(event);
1890
2120
  }
2121
+ const eventAttribute = `[${ATTRIBUTE_DATA_EVENT}]`;
1891
2122
  const mapped$1 = /* @__PURE__ */ new WeakMap();
2123
+ const tableClassName = `.${CSS_TABLE}`;
1892
2124
  on(document, "click", onClick);
1893
2125
  on(document, "keydown", onKeydown, { passive: false });
1894
2126
  //#endregion
2127
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/number.mjs
2128
+ /**
2129
+ * Clamp a number between a minimum and maximum value
2130
+ * @param value Value to clamp
2131
+ * @param minimum Minimum value
2132
+ * @param maximum Maximum value
2133
+ * @param loop If `true`, the value will loop around when smaller than the minimum or larger than the maximum _(defaults to `false`)_
2134
+ * @returns Clamped value
2135
+ */
2136
+ function clamp(value, minimum, maximum, loop) {
2137
+ if (![
2138
+ value,
2139
+ minimum,
2140
+ maximum
2141
+ ].every(isNumber)) return NaN;
2142
+ if (value < minimum) return loop === true ? maximum : minimum;
2143
+ return value > maximum ? loop === true ? minimum : maximum : value;
2144
+ }
2145
+ /**
2146
+ * Get the number value from an unknown value _(based on Lodash)_
2147
+ * @param value Original value
2148
+ * @returns Original value as a number, or `NaN` if the value is unable to be parsed
2149
+ */
2150
+ function getNumber(value) {
2151
+ if (typeof value === "number") return value;
2152
+ if (typeof value === "bigint" || typeof value === "boolean") return Number(value);
2153
+ if (value == null || typeof value === "symbol") return NaN;
2154
+ if (typeof value === "function") return getNumber(value());
2155
+ let parsed = value.valueOf();
2156
+ if (typeof parsed === "object") parsed = parsed.toString();
2157
+ if (typeof parsed !== "string") return getNumber(parsed);
2158
+ const trimmed = parsed.trim();
2159
+ if (trimmed.length === 0) return NaN;
2160
+ if (EXPRESSION_ZEROISH.test(parsed)) return 0;
2161
+ const isBinary = EXPRESSION_BINARY.test(trimmed);
2162
+ if (isBinary || EXPRESSION_OCTAL.test(trimmed)) return Number.parseInt(trimmed.slice(2), isBinary ? 2 : OCTAL_VALUE);
2163
+ return Number(EXPRESSION_HEX.test(trimmed) ? trimmed : trimmed.replace(EXPRESSION_UNDERSCORE, ""));
2164
+ }
2165
+ const EXPRESSION_BINARY = /^0b[01]+$/i;
2166
+ const EXPRESSION_HEX = /^0x[0-9a-f]+$/i;
2167
+ const EXPRESSION_OCTAL = /^0o[0-7]+$/i;
2168
+ const EXPRESSION_UNDERSCORE = /_/g;
2169
+ const EXPRESSION_ZEROISH = /^\s*0+\s*$/;
2170
+ const OCTAL_VALUE = 8;
2171
+ //#endregion
2172
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/sized.mjs
2173
+ function getSizedMaximum(first, second) {
2174
+ let actual;
2175
+ if (typeof first === "number") actual = first;
2176
+ else actual = typeof second === "number" ? second : MAXIMUM_DEFAULT;
2177
+ return clamp(actual, 1, MAXIMUM_ABSOLUTE);
2178
+ }
2179
+ const MAXIMUM_ABSOLUTE = 16777216;
2180
+ const MAXIMUM_DEFAULT = 1048576;
2181
+ //#endregion
2182
+ //#region node_modules/@oscarpalmer/atoms/dist/sized/map.mjs
2183
+ /**
2184
+ * A Map with a maximum size
2185
+ *
2186
+ * Behavior is similar to a _LRU_-cache, where the least recently used entries are removed
2187
+ */
2188
+ var SizedMap = class extends Map {
2189
+ /**
2190
+ * The maximum size of the Map
2191
+ */
2192
+ #maximumSize;
2193
+ /**
2194
+ * Is the Map full?
2195
+ */
2196
+ get full() {
2197
+ return this.size >= this.#maximumSize;
2198
+ }
2199
+ get maximum() {
2200
+ return this.#maximumSize;
2201
+ }
2202
+ constructor(first, second) {
2203
+ const maximum = getSizedMaximum(first, second);
2204
+ super();
2205
+ this.#maximumSize = maximum;
2206
+ if (Array.isArray(first)) {
2207
+ const { length } = first;
2208
+ if (length <= maximum) for (let index = 0; index < length; index += 1) this.set(...first[index]);
2209
+ else for (let index = 0; index < maximum; index += 1) this.set(...first[length - maximum + index]);
2210
+ }
2211
+ }
2212
+ /**
2213
+ * @inheritdoc
2214
+ */
2215
+ get(key) {
2216
+ const value = super.get(key);
2217
+ if (value !== void 0 || this.has(key)) this.set(key, value);
2218
+ return value;
2219
+ }
2220
+ /**
2221
+ * @inheritdoc
2222
+ */
2223
+ set(key, value) {
2224
+ if (this.has(key)) this.delete(key);
2225
+ else if (this.size >= this.#maximumSize) this.delete(this.keys().next().value);
2226
+ return super.set(key, value);
2227
+ }
2228
+ };
2229
+ //#endregion
2230
+ //#region node_modules/@oscarpalmer/atoms/dist/function/memoize.mjs
2231
+ var Memoized = class {
2232
+ #state;
2233
+ /**
2234
+ * Maximum cache size
2235
+ */
2236
+ get maximum() {
2237
+ return this.#state.cache?.maximum ?? NaN;
2238
+ }
2239
+ /**
2240
+ * Current cache size
2241
+ */
2242
+ get size() {
2243
+ return this.#state.cache?.size ?? NaN;
2244
+ }
2245
+ constructor(callback, options) {
2246
+ const cache = new SizedMap(options.cacheSize);
2247
+ const getter = (...parameters) => {
2248
+ const key = options.cacheKey?.(...parameters) ?? (parameters.length === 1 ? parameters[0] : join(parameters.map(getString), SEPARATOR));
2249
+ if (cache.has(key)) return cache.get(key);
2250
+ const value = callback(...parameters);
2251
+ cache.set(key, value);
2252
+ return value;
2253
+ };
2254
+ this.#state = {
2255
+ cache,
2256
+ getter
2257
+ };
2258
+ }
2259
+ /**
2260
+ * Clear the cache
2261
+ */
2262
+ clear() {
2263
+ this.#state.cache?.clear();
2264
+ }
2265
+ /**
2266
+ * Delete a result from the cache
2267
+ * @param key Key to delete
2268
+ * @returns `true` if the key existed and was removed, otherwise `false`
2269
+ */
2270
+ delete(key) {
2271
+ return this.#state.cache?.delete(key) ?? false;
2272
+ }
2273
+ /**
2274
+ * Destroy the instance _(clearing its cache and removing its callback)_
2275
+ */
2276
+ destroy() {
2277
+ this.#state.cache?.clear();
2278
+ this.#state.cache = void 0;
2279
+ this.#state.getter = void 0;
2280
+ }
2281
+ /**
2282
+ * Get a result from the cache
2283
+ * @param key Key to get
2284
+ * @returns Cached result or `undefined` if it does not exist
2285
+ */
2286
+ get(key) {
2287
+ return this.#state.cache?.get(key);
2288
+ }
2289
+ /**
2290
+ * Does the result exist?
2291
+ * @param key Key to check
2292
+ * @returns `true` if the result exists, otherwise `false`
2293
+ */
2294
+ has(key) {
2295
+ return this.#state.cache?.has(key) ?? false;
2296
+ }
2297
+ /**
2298
+ * Run the callback with the provided parameters
2299
+ * @param parameters Parameters to pass to the callback
2300
+ * @returns Cached or computed _(then cached)_ result
2301
+ */
2302
+ run(...parameters) {
2303
+ if (this.#state.cache == null || this.#state.getter == null) throw new Error("The Memoized instance has been destroyed");
2304
+ return this.#state.getter(...parameters);
2305
+ }
2306
+ };
2307
+ function getMemoizationOptions(input) {
2308
+ const { cacheKey, cacheSize } = isPlainObject(input) ? input : {};
2309
+ return {
2310
+ cacheKey: typeof cacheKey === "function" ? cacheKey : void 0,
2311
+ cacheSize: typeof cacheSize === "number" && cacheSize > 0 ? cacheSize : DEFAULT_CACHE_SIZE
2312
+ };
2313
+ }
2314
+ /**
2315
+ * Memoize a function, caching and retrieving results based on the first parameter
2316
+ * @param callback Callback to memoize
2317
+ * @param options Memoization options
2318
+ * @returns Memoized instance
2319
+ */
2320
+ function memoize(callback, options) {
2321
+ return new Memoized(callback, getMemoizationOptions(options));
2322
+ }
2323
+ const DEFAULT_CACHE_SIZE = 1024;
2324
+ const SEPARATOR = "_";
2325
+ //#endregion
1895
2326
  //#region node_modules/@oscarpalmer/atoms/dist/string/match.mjs
1896
2327
  /**
1897
2328
  * Check if a string ends with a specified substring
@@ -2107,29 +2538,43 @@ const ARRAY_THRESHOLD = 100;
2107
2538
  const ERROR_PROPERTIES = ["name", "message"];
2108
2539
  const EXPRESSION_PROPERTIES = ["source", "flags"];
2109
2540
  //#endregion
2541
+ //#region src/models/filter.model.ts
2542
+ const FILTER_CONTAINS = "contains";
2543
+ const FILTER_ENDS_WITH = "ends-with";
2544
+ const FILTER_EQUALS = "equals";
2545
+ const FILTER_GREATER_THAN = "greater-than";
2546
+ const FILTER_GREATER_THAN_OR_EQUAL = "greater-than-or-equal";
2547
+ const FILTER_LESS_THAN = "less-than";
2548
+ const FILTER_LESS_THAN_OR_EQUAL = "less-than-or-equal";
2549
+ const FILTER_NOT_CONTAINS = "not-contains";
2550
+ const FILTER_NOT_EQUALS = "not-equals";
2551
+ const FILTER_STARTS_WITH = "starts-with";
2552
+ //#endregion
2110
2553
  //#region src/managers/filter.manager.ts
2111
2554
  var FilterManager = class {
2112
- handlers = Object.freeze({
2555
+ handlers = {
2113
2556
  add: (item) => this.add(item),
2114
2557
  clear: () => this.clear(),
2115
2558
  remove: (value) => this.remove(value),
2116
2559
  set: (items) => this.set(items)
2117
- });
2560
+ };
2118
2561
  items = {};
2119
2562
  constructor(state) {
2120
2563
  this.state = state;
2121
2564
  }
2122
2565
  add(item) {
2123
- if (this.items[item.field] == null) this.items[item.field] = [];
2124
- else if (this.items[item.field].findIndex((existing) => equal(existing, item)) > -1) return;
2125
- this.items[item.field].push(item);
2566
+ const { items, state } = this;
2567
+ if (items[item.key] == null) items[item.key] = [];
2568
+ else if (items[item.key].findIndex((existing) => equal(existing, item)) > -1) return;
2569
+ items[item.key].push(item);
2570
+ state.managers.event.emit("filter:add", [item]);
2126
2571
  this.filter();
2127
2572
  }
2128
2573
  clear() {
2129
- if (Object.keys(this.items).length > 0) {
2130
- this.items = {};
2131
- this.filter();
2132
- }
2574
+ if (Object.keys(this.items).length === 0) return;
2575
+ this.items = {};
2576
+ this.state.managers.event.emit("filter:clear");
2577
+ this.filter();
2133
2578
  }
2134
2579
  destroy() {
2135
2580
  this.handlers = void 0;
@@ -2140,18 +2585,18 @@ var FilterManager = class {
2140
2585
  const { state } = this;
2141
2586
  const filtered = [];
2142
2587
  const filters = Object.entries(this.items);
2143
- const itemsLength = state.managers.data.state.items.original.length;
2588
+ const itemsLength = state.managers.data.state.keys.original.length;
2144
2589
  rowLoop: for (let itemIndex = 0; itemIndex < itemsLength; itemIndex += 1) {
2145
- const item = state.managers.data.state.items.original[itemIndex];
2146
- if (item instanceof GroupComponent) {
2590
+ const item = state.managers.data.state.keys.original[itemIndex];
2591
+ if (isGroupKey(item)) {
2147
2592
  filtered.push(item);
2148
2593
  continue;
2149
2594
  }
2150
2595
  const row = state.managers.data.state.values.mapped.get(item);
2151
2596
  if (row == null) continue;
2152
2597
  filterLoop: for (let filterIndex = 0; filterIndex < filters.length; filterIndex += 1) {
2153
- const [field, items] = filters[filterIndex];
2154
- const value = row[field];
2598
+ const [key, items] = filters[filterIndex];
2599
+ const value = row[key];
2155
2600
  for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) {
2156
2601
  const filter = items[itemIndex];
2157
2602
  if (comparators[filter.comparison](value, filter.value)) continue filterLoop;
@@ -2160,26 +2605,31 @@ var FilterManager = class {
2160
2605
  }
2161
2606
  filtered.push(item);
2162
2607
  }
2163
- state.managers.data.state.items.active = filtered;
2608
+ state.managers.data.state.keys.active = filtered;
2164
2609
  if (state.managers.sort.items.length > 0) state.managers.sort.sort();
2165
2610
  else state.managers.render.update(true, true);
2166
2611
  }
2167
2612
  remove(value) {
2613
+ const removed = [];
2168
2614
  if (typeof value === "string") {
2169
2615
  if (this.items[value] == null) return;
2170
2616
  const keyed = {};
2171
- const filters = Object.keys(this.items);
2172
- const { length } = filters;
2617
+ const keys = Object.keys(this.items);
2618
+ const { length } = keys;
2173
2619
  for (let index = 0; index < length; index += 1) {
2174
- const field = filters[index];
2175
- if (field !== value) keyed[field] = this.items[field];
2620
+ const key = keys[index];
2621
+ if (key === value) removed.push(...this.items[key]);
2622
+ else keyed[key] = this.items[key];
2176
2623
  }
2177
2624
  this.items = keyed;
2178
2625
  } else {
2179
- const { field } = value;
2180
- if (this.items[field] == null) return;
2181
- if (this.items[field].findIndex((item) => equal(item, value)) === -1) return;
2626
+ const { key } = value;
2627
+ if (this.items[key] == null) return;
2628
+ const index = this.items[key].findIndex((item) => equal(item, value));
2629
+ if (index === -1) return;
2630
+ removed.push(this.items[key][index]);
2182
2631
  }
2632
+ this.state.managers.event.emit("filter:remove", removed);
2183
2633
  this.filter();
2184
2634
  }
2185
2635
  set(items) {
@@ -2187,24 +2637,24 @@ var FilterManager = class {
2187
2637
  const { length } = items;
2188
2638
  for (let index = 0; index < length; index += 1) {
2189
2639
  const item = items[index];
2190
- keyed[item.field] ??= [];
2191
- keyed[item.field].push(item);
2640
+ keyed[item.key] ??= [];
2641
+ keyed[item.key].push(item);
2192
2642
  }
2193
2643
  this.items = keyed;
2194
2644
  this.filter();
2195
2645
  }
2196
2646
  };
2197
2647
  const comparators = {
2198
- contains: (row, filter) => includes(getString(row), getString(filter), true),
2199
- "ends-with": (row, filter) => endsWith(getString(row), getString(filter), true),
2200
- equals: (row, filter) => equalizer(row, filter),
2201
- "greater-than": (row, filter) => getNumber(row) > getNumber(filter),
2202
- "greater-than-or-equal": (row, filter) => getNumber(row) >= getNumber(filter),
2203
- "less-than": (row, filter) => getNumber(row) < getNumber(filter),
2204
- "less-than-or-equal": (row, filter) => getNumber(row) <= getNumber(filter),
2205
- "not-contains": (row, filter) => !includes(getString(row), getString(filter), true),
2206
- "not-equals": (row, filter) => !equalizer(row, filter),
2207
- "starts-with": (row, filter) => startsWith(getString(row), getString(filter), true)
2648
+ [FILTER_CONTAINS]: (row, filter) => includes(getString(row), getString(filter), true),
2649
+ [FILTER_ENDS_WITH]: (row, filter) => endsWith(getString(row), getString(filter), true),
2650
+ [FILTER_EQUALS]: (row, filter) => equalizer(row, filter),
2651
+ [FILTER_GREATER_THAN]: (row, filter) => getNumber(row) > getNumber(filter),
2652
+ [FILTER_GREATER_THAN_OR_EQUAL]: (row, filter) => getNumber(row) >= getNumber(filter),
2653
+ [FILTER_LESS_THAN]: (row, filter) => getNumber(row) < getNumber(filter),
2654
+ [FILTER_LESS_THAN_OR_EQUAL]: (row, filter) => getNumber(row) <= getNumber(filter),
2655
+ [FILTER_NOT_CONTAINS]: (row, filter) => !includes(getString(row), getString(filter), true),
2656
+ [FILTER_NOT_EQUALS]: (row, filter) => !equalizer(row, filter),
2657
+ [FILTER_STARTS_WITH]: (row, filter) => startsWith(getString(row), getString(filter), true)
2208
2658
  };
2209
2659
  const equalizer = equal.initialize({ ignoreCase: true });
2210
2660
  //#endregion
@@ -2212,28 +2662,34 @@ const equalizer = equal.initialize({ ignoreCase: true });
2212
2662
  var GroupManager = class {
2213
2663
  collapsed = /* @__PURE__ */ new Set();
2214
2664
  enabled = false;
2215
- field;
2216
- handlers = Object.freeze({ set: (group) => {
2217
- if (group === this.field) return;
2665
+ key;
2666
+ handlers = { set: (group) => {
2667
+ if (group === this.key) return;
2218
2668
  this.enabled = !isNullableOrWhitespace(group);
2219
- this.field = group ?? "";
2669
+ this.key = group ?? "";
2220
2670
  this.state.managers.data.set(this.state.managers.data.get());
2221
- } });
2671
+ } };
2222
2672
  items = [];
2673
+ mapped = /* @__PURE__ */ new Map();
2223
2674
  order = {};
2224
2675
  constructor(state) {
2225
2676
  this.state = state;
2226
2677
  if (isNullableOrWhitespace(state.options.grouping)) return;
2227
2678
  this.enabled = true;
2228
- this.field = state.options.grouping;
2679
+ this.key = state.options.grouping;
2229
2680
  }
2230
- add(group) {
2681
+ add(group, emit) {
2231
2682
  this.set([...this.items, group]);
2683
+ if (emit) this.state.managers.event.emit(EVENT_GROUP_ADD, [getGroup(group)]);
2232
2684
  }
2233
2685
  clear() {
2686
+ if (this.items.length === 0) return;
2234
2687
  const groups = this.items.splice(0);
2235
2688
  const { length } = groups;
2236
- for (let index = 0; index < length; index += 1) this.remove(groups[index]);
2689
+ for (let index = 0; index < length; index += 1) this.remove(groups[index], false);
2690
+ this.collapsed.clear();
2691
+ this.set([]);
2692
+ this.state.managers.event.emit(EVENT_GROUP_CLEAR);
2237
2693
  }
2238
2694
  destroy() {
2239
2695
  const groups = this.items.splice(0);
@@ -2243,46 +2699,48 @@ var GroupManager = class {
2243
2699
  this.handlers = void 0;
2244
2700
  this.state = void 0;
2245
2701
  }
2246
- get(value) {
2702
+ getForKey(key) {
2703
+ return this.mapped.get(key);
2704
+ }
2705
+ getForValue(value) {
2247
2706
  const asString = getString(value);
2248
2707
  return this.items.find((item) => item.value.stringified === asString);
2249
2708
  }
2250
2709
  handle(button) {
2251
- const value = button.dataset.key?.replace(`tabela_${this.state.id}_group:`, "");
2252
- const group = this.get(value);
2710
+ const key = button.dataset.key?.replace(`${this.state.prefix}_`, "");
2711
+ const group = this.getForKey(key ?? "");
2253
2712
  if (group == null) return;
2254
2713
  const { collapsed, items, state } = this;
2255
2714
  group.expanded = !group.expanded;
2256
2715
  const index = items.indexOf(group);
2257
- let first = state.managers.data.state.items.original.indexOf(items[index]) + 1;
2258
- const last = items[index + 1] == null ? state.managers.data.state.items.original.length - 1 : state.managers.data.state.items.original.indexOf(items[index + 1]) - 1;
2716
+ let first = state.managers.data.state.keys.original.indexOf(group.key) + 1;
2717
+ const last = items[index + 1] == null ? state.managers.data.state.keys.original.length - 1 : state.managers.data.state.keys.original.indexOf(items[index + 1].key) - 1;
2259
2718
  for (; first <= last; first += 1) {
2260
- const key = state.managers.data.state.items.original[first];
2719
+ const key = state.managers.data.state.keys.original[first];
2261
2720
  if (group.expanded) collapsed.delete(key);
2262
2721
  else collapsed.add(key);
2263
2722
  }
2723
+ state.managers.event.emit(EVENT_GROUP_TOGGLE, {
2724
+ collapsed: group.expanded ? [] : [getGroup(group)],
2725
+ expanded: group.expanded ? [getGroup(group)] : []
2726
+ });
2264
2727
  if (Object.keys(state.managers.filter.items).length > 0) state.managers.filter.filter();
2265
2728
  else if (state.managers.sort.items.length > 0) state.managers.sort.sort();
2266
2729
  else state.managers.render.update(true, true);
2267
2730
  }
2268
- remove(group) {
2731
+ remove(group, update) {
2269
2732
  removeGroup(group);
2733
+ if (!update) return;
2270
2734
  this.set(this.items.filter((item) => item !== group));
2735
+ this.state.managers.event.emit(EVENT_GROUP_REMOVE, [getGroup(group)]);
2271
2736
  }
2272
2737
  set(items) {
2273
- this.items = sort(items, (item) => item.label);
2738
+ this.items = sort(items, (first, second) => compare(first.label, second.label));
2739
+ this.mapped = toMap(items, (group) => group.key);
2274
2740
  this.order = toRecord(items, (group) => group.value.stringified, (_, index) => index);
2275
2741
  }
2276
2742
  };
2277
2743
  //#endregion
2278
- //#region src/helpers/misc.helpers.ts
2279
- function getKey(value) {
2280
- if (typeof value === "number") return value;
2281
- if (typeof value !== "string") return;
2282
- return integerExpression.test(value) ? Number.parseInt(value, 10) : value;
2283
- }
2284
- const integerExpression = /^\d+$/;
2285
- //#endregion
2286
2744
  //#region src/managers/navigation.manager.ts
2287
2745
  var NavigationManager = class {
2288
2746
  active;
@@ -2295,59 +2753,63 @@ var NavigationManager = class {
2295
2753
  handle(event) {
2296
2754
  if (!allKeys.has(event.key)) return;
2297
2755
  event.preventDefault();
2298
- const { components, id, managers } = this.state;
2299
- const activeDescendant = components.body.elements.group.getAttribute("aria-activedescendant");
2300
- const { items } = managers.data;
2301
- const { length } = items;
2756
+ const { components, managers } = this.state;
2757
+ const activeDescendant = components.body.elements.group.getAttribute(ARIA_ACTIVEDESCENDANT);
2758
+ const { keys } = managers.data;
2759
+ const { length } = keys;
2302
2760
  let next;
2303
2761
  if (isNullableOrWhitespace(activeDescendant)) next = getDefaultIndex(event.key, length);
2304
- else next = getIndex(this.state, event, activeDescendant, id);
2305
- if (next != null) this.setActive(items.at(next));
2762
+ else next = getIndex(this.state, event, activeDescendant);
2763
+ if (next != null) this.setActive(keys.at(next));
2306
2764
  }
2307
2765
  setActive(item, scroll) {
2308
- const { components, id, managers, options } = this.state;
2766
+ const { components, managers, options, prefix } = this.state;
2309
2767
  this.active = item;
2310
- const active = components.body.elements.group.querySelectorAll("[data-active=\"true\"]");
2311
- for (const item of active) item.setAttribute("data-active", "false");
2312
- const component = item instanceof GroupComponent ? item : managers.row.get(item, false);
2768
+ const active = components.body.elements.group.querySelectorAll(attributeDataActiveTrue);
2769
+ for (const item of active) item.setAttribute(ATTRIBUTE_DATA_ACTIVE, "false");
2770
+ const component = isGroupKey(item) ? managers.group.getForKey(item) : managers.row.get(item, false);
2313
2771
  if (component != null) {
2314
- component.element?.setAttribute("data-active", "true");
2772
+ component.element?.setAttribute(ATTRIBUTE_DATA_ACTIVE, "true");
2315
2773
  if (scroll ?? true) if (component.element == null) components.body.elements.group.scrollTo({
2316
2774
  top: managers.data.getIndex(item) * options.rowHeight,
2317
2775
  behavior: "smooth"
2318
2776
  });
2319
2777
  else component.element.scrollIntoView({ block: "nearest" });
2320
2778
  }
2321
- components.body.elements.group.setAttribute("aria-activedescendant", component == null ? "" : `tabela_${id}_${component.key}`);
2779
+ components.body.elements.group.setAttribute(ARIA_ACTIVEDESCENDANT, component == null ? "" : `${prefix}${component.key}`);
2322
2780
  }
2323
2781
  };
2324
2782
  function getDefaultIndex(key, max) {
2325
2783
  switch (true) {
2326
2784
  case negativeDefaultKeys.has(key): return -1;
2327
- case key === "PageDown": return Math.min(9, max - 1);
2328
- case key === "PageUp": return max < 10 ? 0 : max - 10;
2785
+ case key === KEY_PAGE_DOWN: return Math.min(9, max - 1);
2786
+ case key === KEY_PAGE_UP: return max < 10 ? 0 : max - 10;
2329
2787
  default: return 0;
2330
2788
  }
2331
2789
  }
2332
- function getIndex(state, event, active, id) {
2333
- const key = getKey(active.replace(`tabela_${id}_`, ""));
2790
+ function getIndex(state, event, active) {
2791
+ const key = getKey(active.replace(state.prefix, ""));
2334
2792
  if (key == null) return;
2335
- if (absoluteKeys.has(event.key)) return event.key === "Home" ? 0 : state.managers.data.size - 1;
2336
- return clamp(state.managers.data.getIndex(key) + getOffset(event.key), 0, state.managers.data.size - 1, true);
2337
- }
2338
- function getOffset(key) {
2339
- switch (key) {
2340
- case "ArrowDown": return 1;
2341
- case "ArrowUp": return -1;
2342
- case "PageDown": return 10;
2343
- case "PageUp": return -10;
2344
- default: return 0;
2345
- }
2346
- }
2347
- const absoluteKeys = new Set(["End", "Home"]);
2348
- const arrowKeys = new Set(["ArrowDown", "ArrowUp"]);
2349
- const negativeDefaultKeys = new Set(["ArrowUp", "End"]);
2350
- const pageKeys = new Set(["PageDown", "PageUp"]);
2793
+ if (absoluteKeys.has(event.key)) return event.key === KEY_HOME ? 0 : state.managers.data.size - 1;
2794
+ return clamp(state.managers.data.getIndex(key) + (offset[event.key] ?? 0), 0, state.managers.data.size - 1, true);
2795
+ }
2796
+ const KEY_ARROW_DOWN = "ArrowDown";
2797
+ const KEY_ARROW_UP = "ArrowUp";
2798
+ const KEY_END = "End";
2799
+ const KEY_HOME = "Home";
2800
+ const KEY_PAGE_DOWN = "PageDown";
2801
+ const KEY_PAGE_UP = "PageUp";
2802
+ const absoluteKeys = new Set([KEY_END, KEY_HOME]);
2803
+ const arrowKeys = new Set([KEY_ARROW_DOWN, KEY_ARROW_UP]);
2804
+ const attributeDataActiveTrue = `[${ATTRIBUTE_DATA_ACTIVE}="true"]`;
2805
+ const negativeDefaultKeys = new Set([KEY_ARROW_UP, KEY_END]);
2806
+ const offset = {
2807
+ [KEY_ARROW_DOWN]: 1,
2808
+ [KEY_ARROW_UP]: -1,
2809
+ [KEY_PAGE_DOWN]: 10,
2810
+ [KEY_PAGE_UP]: -10
2811
+ };
2812
+ const pageKeys = new Set([KEY_PAGE_DOWN, KEY_PAGE_UP]);
2351
2813
  const allKeys = new Set([
2352
2814
  ...absoluteKeys,
2353
2815
  ...arrowKeys,
@@ -2365,31 +2827,33 @@ function removeRow(pool, row) {
2365
2827
  row.cells = {};
2366
2828
  }
2367
2829
  function renderRow(state, row) {
2368
- const element = row.element ?? state.managers.render.pool.rows.shift() ?? createRow();
2830
+ const { managers, options, prefix } = state;
2831
+ const element = row.element ?? managers.render.pool.rows.shift() ?? createRow(options.rowHeight);
2369
2832
  row.element = element;
2370
2833
  element.innerHTML = "";
2371
- const selected = state.managers.selection.items.has(row.key);
2834
+ const selected = managers.selection.items.has(row.key);
2372
2835
  const key = String(row.key);
2373
2836
  setAttributes(element, {
2374
- "aria-selected": String(selected),
2375
- "data-active": String(state.managers.navigation.active === row.key),
2376
- "data-event": "row",
2377
- "data-key": key,
2378
- id: `tabela_${state.id}_${key}`
2837
+ [ARIA_SELECTED]: String(selected),
2838
+ [ATTRIBUTE_DATA_ACTIVE]: String(managers.navigation.active === row.key),
2839
+ [ATTRIBUTE_DATA_EVENT]: "row",
2840
+ [ATTRIBUTE_DATA_KEY]: key,
2841
+ id: `${prefix}${key}`
2379
2842
  });
2380
- element.classList.add(CSS_TABELA_ROW_BODY);
2381
- if (selected) element.classList.add(CSS_TABELA_ROW_SELECTED);
2382
- else element.classList.remove(CSS_TABELA_ROW_SELECTED);
2383
- const columns = state.managers.column.items;
2843
+ element.classList.add(CSS_ROW_BODY);
2844
+ if (selected) element.classList.add(CSS_ROW_SELECTED);
2845
+ else element.classList.remove(CSS_ROW_SELECTED);
2846
+ const columns = managers.column.items;
2384
2847
  const { length } = columns;
2385
- const data = state.managers.data.state.values.mapped.get(row.key);
2848
+ const data = managers.data.state.values.mapped.get(row.key);
2386
2849
  if (data == null) return;
2387
2850
  for (let index = 0; index < length; index += 1) {
2388
2851
  const { options } = columns[index];
2389
- state.managers.render.pool.cells[options.field] ??= [];
2390
- const cell = state.managers.render.pool.cells[columns[index].options.field].shift() ?? createCell(options.width);
2391
- cell.textContent = String(getValue(data, options.field));
2392
- row.cells[options.field] = cell;
2852
+ const { key, width } = options;
2853
+ managers.render.pool.cells[key] ??= [];
2854
+ const cell = managers.render.pool.cells[key].shift() ?? createCell(width);
2855
+ cell.textContent = String(getValue(data, key));
2856
+ row.cells[key] = cell;
2393
2857
  element.append(cell);
2394
2858
  }
2395
2859
  }
@@ -2405,9 +2869,9 @@ var RowComponent = class {
2405
2869
  function getRange(state, down) {
2406
2870
  const { element, managers, options } = state;
2407
2871
  const { clientHeight, scrollTop } = element;
2408
- const { items } = managers.data;
2872
+ const { keys } = managers.data;
2409
2873
  const firstIndex = Math.floor(scrollTop / options.rowHeight);
2410
- const lastIndex = items.length - managers.group.collapsed.size - 1;
2874
+ const lastIndex = keys.length - managers.group.collapsed.size - 1;
2411
2875
  const last = Math.min(lastIndex, Math.ceil((scrollTop + clientHeight) / options.rowHeight) - 1);
2412
2876
  const visible = clientHeight / options.rowHeight;
2413
2877
  const before = Math.ceil(visible) * (down ? 1 : 2);
@@ -2438,7 +2902,10 @@ var RenderManager = class {
2438
2902
  rows: []
2439
2903
  };
2440
2904
  state;
2441
- visible = /* @__PURE__ */ new Map();
2905
+ visible = {
2906
+ indiced: /* @__PURE__ */ new Map(),
2907
+ keys: /* @__PURE__ */ new Set()
2908
+ };
2442
2909
  constructor(state) {
2443
2910
  this.listener = on(state.element, "scroll", onScroll.bind(this));
2444
2911
  this.state = {
@@ -2450,7 +2917,8 @@ var RenderManager = class {
2450
2917
  destroy() {
2451
2918
  const { listener, pool, visible } = this;
2452
2919
  listener();
2453
- visible.clear();
2920
+ visible.indiced.clear();
2921
+ visible.keys.clear();
2454
2922
  const cells = Object.values(pool.cells).flat();
2455
2923
  let { length } = cells;
2456
2924
  for (let index = 0; index < length; index += 1) cells[index].remove();
@@ -2464,18 +2932,18 @@ var RenderManager = class {
2464
2932
  this.state = void 0;
2465
2933
  this.visible = void 0;
2466
2934
  }
2467
- removeCells(fields) {
2935
+ removeCells(keys) {
2468
2936
  const { pool, state, visible } = this;
2469
- const { length } = fields;
2470
- for (let index = 0; index < length; index += 1) delete pool.cells[fields[index]];
2471
- for (const [, key] of visible) {
2472
- if (key instanceof GroupComponent) continue;
2937
+ const { length } = keys;
2938
+ for (let index = 0; index < length; index += 1) delete pool.cells[keys[index]];
2939
+ for (const [, key] of visible.indiced) {
2940
+ if (isGroupKey(key)) continue;
2473
2941
  const row = state.managers.row.get(key, false);
2474
2942
  if (row == null || row.element == null) continue;
2475
2943
  for (let index = 0; index < length; index += 1) {
2476
- row.cells[fields[index]].innerHTML = "";
2477
- row.cells[fields[index]].remove();
2478
- delete row.cells[fields[index]];
2944
+ row.cells[keys[index]].innerHTML = "";
2945
+ row.cells[keys[index]].remove();
2946
+ delete row.cells[keys[index]];
2479
2947
  }
2480
2948
  }
2481
2949
  }
@@ -2492,52 +2960,60 @@ var RenderManager = class {
2492
2960
  const range = getRange(state, down);
2493
2961
  for (let index = range.start; index <= range.end; index += 1) indices.add(index);
2494
2962
  let remove = rerender ?? false;
2495
- for (const [index, key] of visible) {
2496
- if (key instanceof GroupComponent) {
2963
+ for (const [index, key] of visible.indiced) {
2964
+ if (isGroupKey(key)) {
2497
2965
  if (remove || !indices.has(index)) {
2498
- visible.delete(index);
2499
- key.element?.remove();
2966
+ visible.indiced.delete(index);
2967
+ visible.keys.delete(key);
2968
+ state.managers.group.getForKey(key)?.element?.remove();
2500
2969
  }
2501
2970
  continue;
2502
2971
  }
2503
2972
  const row = managers.row.get(key, false);
2504
2973
  if (remove || row == null || !indices.has(index) || managers.group.collapsed.has(key)) {
2505
- visible.delete(index);
2974
+ visible.indiced.delete(index);
2975
+ visible.keys.delete(key);
2506
2976
  if (row != null) removeRow(pool, row);
2507
2977
  }
2508
2978
  }
2509
2979
  const fragment = this.getFragment();
2510
- const { items } = managers.data;
2980
+ const { keys } = managers.data;
2511
2981
  let count = 0;
2512
2982
  let offset = 0;
2513
2983
  for (let index = range.start; index <= range.end + offset; index += 1) {
2514
- if (visible.has(index)) continue;
2515
- const item = items[index];
2516
- if (item instanceof GroupComponent) {
2984
+ if (visible.indiced.has(index)) continue;
2985
+ const key = keys[index];
2986
+ if (isGroupKey(key)) {
2987
+ const group = managers.group.getForKey(key);
2988
+ if (group == null) continue;
2517
2989
  count += 1;
2518
- renderGroup(state, item);
2519
- visible.set(index, item);
2520
- if (item.element != null) {
2521
- item.element.style.transform = `translateY(${(index - offset) * options.rowHeight}px)`;
2522
- fragment.append(item.element);
2990
+ renderGroup(state, group);
2991
+ visible.indiced.set(index, group.key);
2992
+ visible.keys.add(group.key);
2993
+ if (group.element != null) {
2994
+ group.element.style.transform = `translateY(${(index - offset) * options.rowHeight}px)`;
2995
+ fragment.append(group.element);
2523
2996
  }
2524
2997
  continue;
2525
2998
  }
2526
- const row = managers.row.get(item, true);
2999
+ const row = managers.row.get(key, true);
2527
3000
  if (row == null) continue;
2528
- if (managers.group.collapsed.has(item)) {
3001
+ if (managers.group.collapsed.has(key)) {
2529
3002
  offset += 1;
2530
3003
  continue;
2531
3004
  }
2532
3005
  count += 1;
2533
3006
  renderRow(state, row);
2534
- visible.set(index, item);
3007
+ visible.indiced.set(index, key);
3008
+ visible.keys.add(key);
2535
3009
  if (row.element != null) {
2536
3010
  row.element.style.transform = `translateY(${(index - offset) * options.rowHeight}px)`;
2537
3011
  fragment.append(row.element);
2538
3012
  }
2539
3013
  }
2540
- if (count > 0) components.body.elements.group[down ? "append" : "prepend"](fragment);
3014
+ if (count === 0) return;
3015
+ if (down) components.body.elements.group.append(fragment);
3016
+ else components.body.elements.group.prepend(fragment);
2541
3017
  }
2542
3018
  };
2543
3019
  //#endregion
@@ -2580,7 +3056,7 @@ var RowManager = class {
2580
3056
  }
2581
3057
  update(key) {
2582
3058
  const row = this.components.get(key);
2583
- if (row != null) renderRow(this.state, row);
3059
+ if (row?.element != null) renderRow(this.state, row);
2584
3060
  }
2585
3061
  };
2586
3062
  //#endregion
@@ -2592,13 +3068,13 @@ const preventSelection = toggleStyles(document.body, {
2592
3068
  //#endregion
2593
3069
  //#region src/managers/selection.manager.ts
2594
3070
  var SelectionManager = class {
2595
- handlers = Object.freeze({
3071
+ handlers = {
2596
3072
  add: (keys) => this.add(keys),
2597
3073
  clear: () => this.clear(),
2598
3074
  remove: (keys) => this.remove(keys),
2599
3075
  set: (keys) => this.set(keys),
2600
3076
  toggle: () => this.toggle()
2601
- });
3077
+ };
2602
3078
  items = /* @__PURE__ */ new Set();
2603
3079
  last;
2604
3080
  constructor(state) {
@@ -2631,7 +3107,7 @@ var SelectionManager = class {
2631
3107
  this.state = void 0;
2632
3108
  }
2633
3109
  handle(event, target) {
2634
- const key = getKey(target.getAttribute("data-key"));
3110
+ const key = getKey(target.getAttribute(ATTRIBUTE_DATA_KEY));
2635
3111
  if (key == null) return;
2636
3112
  const { items } = this;
2637
3113
  if (event.shiftKey) {
@@ -2651,18 +3127,18 @@ var SelectionManager = class {
2651
3127
  range(from, to) {
2652
3128
  const { state } = this;
2653
3129
  const keyed = isKey(from) && isKey(to);
2654
- const fromKey = keyed ? from : getKey(from.getAttribute("data-key"));
2655
- const toKey = keyed ? to : getKey(to.getAttribute("data-key"));
3130
+ const fromKey = keyed ? from : getKey(from.getAttribute(ATTRIBUTE_DATA_KEY));
3131
+ const toKey = keyed ? to : getKey(to.getAttribute(ATTRIBUTE_DATA_KEY));
2656
3132
  if (fromKey === toKey) return;
2657
- const { items } = state.managers.data;
3133
+ const { keys } = state.managers.data;
2658
3134
  const fromIndex = state.managers.data.getIndex(fromKey);
2659
3135
  const toIndex = state.managers.data.getIndex(toKey);
2660
3136
  if (fromIndex === -1 || toIndex === -1) return;
2661
3137
  const [start, end] = fromIndex < toIndex ? [fromIndex, toIndex] : [toIndex, fromIndex];
2662
3138
  const selected = [];
2663
3139
  for (let index = start; index <= end; index += 1) {
2664
- const item = items[index];
2665
- if (!(item instanceof GroupComponent)) selected.push(item);
3140
+ const key = keys[index];
3141
+ if (!isGroupKey(key)) selected.push(key);
2666
3142
  }
2667
3143
  if (keyed) this.add(selected);
2668
3144
  else this.set(selected);
@@ -2688,9 +3164,9 @@ var SelectionManager = class {
2688
3164
  }
2689
3165
  toggle() {
2690
3166
  const { items, state } = this;
2691
- const data = state.managers.data.items;
2692
- if (items.size === data.length - state.managers.group.items.length) this.clear();
2693
- else this.set(data.filter((key) => !(key instanceof GroupComponent)));
3167
+ const { keys } = state.managers.data;
3168
+ if (items.size === keys.length - state.managers.group.items.length) this.clear();
3169
+ else this.set(keys.filter((key) => !isGroupKey(key)));
2694
3170
  }
2695
3171
  update(removed) {
2696
3172
  const { state } = this;
@@ -2706,19 +3182,19 @@ var SelectionManager = class {
2706
3182
  const { key, removed } = items[index];
2707
3183
  const element = state.managers.row.get(key, false)?.element;
2708
3184
  if (element == null) continue;
2709
- setAttribute(element, "aria-selected", String(!removed));
2710
- if (removed) element.classList.remove(CSS_TABELA_ROW_SELECTED);
2711
- else element.classList.add(CSS_TABELA_ROW_SELECTED);
3185
+ setAttribute(element, ARIA_SELECTED, String(!removed));
3186
+ if (removed) element.classList.remove(CSS_ROW_SELECTED);
3187
+ else element.classList.add(CSS_ROW_SELECTED);
2712
3188
  }
2713
3189
  }
2714
3190
  };
2715
3191
  function getPlaceholder() {
2716
- placeholder ??= createElement("div", { className: CSS_TABELA_SELECTION }, {}, {});
3192
+ placeholder ??= createElement("div", { className: CSS_SELECTION });
2717
3193
  return placeholder;
2718
3194
  }
2719
3195
  function onMouseDown(event) {
2720
3196
  if (shifted) {
2721
- const row = findAncestor(event.target, `.${CSS_TABELA_ROW_BODY}`);
3197
+ const row = findAncestor(event.target, `.${CSS_ROW_BODY}`);
2722
3198
  if (!(row instanceof HTMLElement)) return;
2723
3199
  startElement = row;
2724
3200
  startPosition = getPosition(event);
@@ -2746,11 +3222,11 @@ function onMouseUp(event) {
2746
3222
  preventSelection.remove();
2747
3223
  }
2748
3224
  getPlaceholder().remove();
2749
- const row = findAncestor(event.target, ".tabela__row--body");
3225
+ const row = findAncestor(event.target, bodyRowSelector);
2750
3226
  if (row instanceof HTMLElement) {
2751
3227
  endElement = row;
2752
- const endTable = findAncestor(endElement, ".tabela__table");
2753
- const startTable = findAncestor(startElement, ".tabela__table");
3228
+ const endTable = findAncestor(endElement, tableSelector);
3229
+ const startTable = findAncestor(startElement, tableSelector);
2754
3230
  if (startTable != null && startTable === endTable) mapped.get(startTable)?.range(startElement, endElement);
2755
3231
  }
2756
3232
  endElement = void 0;
@@ -2758,7 +3234,7 @@ function onMouseUp(event) {
2758
3234
  startPosition = void 0;
2759
3235
  }
2760
3236
  function onShift(event, value) {
2761
- if (event.key === "Shift") shifted = value;
3237
+ if (event.key === KEY_SHIFT) shifted = value;
2762
3238
  }
2763
3239
  function onShiftDown(event) {
2764
3240
  onShift(event, true);
@@ -2766,7 +3242,10 @@ function onShiftDown(event) {
2766
3242
  function onShiftUp(event) {
2767
3243
  onShift(event, false);
2768
3244
  }
3245
+ const KEY_SHIFT = "Shift";
2769
3246
  const mapped = /* @__PURE__ */ new WeakMap();
3247
+ const bodyRowSelector = `.${CSS_ROW_BODY}`;
3248
+ const tableSelector = `.${CSS_TABLE}`;
2770
3249
  let shifted = false;
2771
3250
  let endElement;
2772
3251
  let placeholder;
@@ -2791,14 +3270,14 @@ var StyleManager = class {
2791
3270
  };
2792
3271
  const styling = `/** Table */
2793
3272
 
2794
- :where(.tabela) {
3273
+ :where(.${CSS_WRAPPER}) {
2795
3274
  flex: 1;
2796
3275
  position: relative;
2797
3276
  background-color: var(--oui-absolute);
2798
3277
  border: 1px solid grey;
2799
3278
  }
2800
3279
 
2801
- :where(.tabela__table) {
3280
+ :where(.${CSS_TABLE}) {
2802
3281
  min-height: 24em;
2803
3282
  display: flex;
2804
3283
  flex-flow: column nowrap;
@@ -2810,69 +3289,69 @@ const styling = `/** Table */
2810
3289
 
2811
3290
  /** Row group */
2812
3291
 
2813
- :where(.tabela__rowgroup--header),
2814
- :where(.tabela__rowgroup--footer) {
3292
+ :where(.${CSS_ROWGROUP_HEADER}),
3293
+ :where(.${CSS_ROWGROUP_FOOTER}) {
2815
3294
  background-color: white;
2816
3295
  position: sticky;
2817
3296
  left: 0;
2818
3297
  z-index: 10;
2819
3298
  }
2820
3299
 
2821
- :where(.tabela__rowgroup--header) {
3300
+ :where(.${CSS_ROWGROUP_HEADER}) {
2822
3301
  top: 0;
2823
3302
  }
2824
3303
 
2825
- :where(.tabela__rowgroup--footer) {
3304
+ :where(.${CSS_ROWGROUP_FOOTER}) {
2826
3305
  bottom: 0;
2827
3306
  }
2828
3307
 
2829
- :where(.tabela__rowgroup--body) {
3308
+ :where(.${CSS_ROWGROUP_BODY}) {
2830
3309
  display: flex;
2831
3310
  flex-flow: column nowrap;
2832
3311
  flex: 1;
2833
3312
  }
2834
3313
 
2835
- :where(.tabela__rowgroup--body:focus) {
3314
+ :where(.${CSS_ROWGROUP_BODY}:focus) {
2836
3315
  outline: none;
2837
3316
  }
2838
3317
 
2839
- :where(.tabela:has(.tabela__rowgroup--body:focus-visible)) {
3318
+ :where(.${CSS_WRAPPER}:has(.${CSS_ROWGROUP_BODY}:focus-visible)) {
2840
3319
  outline: 2px solid var(--oui-blue-6);
2841
3320
  outline-offset: 2px;
2842
3321
  }
2843
3322
 
2844
3323
  /** Row */
2845
3324
 
2846
- :where(.tabela__row) {
3325
+ :where(.${CSS_ROW}) {
2847
3326
  width: 100%;
2848
3327
  display: flex;
2849
3328
  flex-flow: row nowrap;
2850
3329
  }
2851
3330
 
2852
- :where(.tabela__row:last-child .tabela__cell) {
3331
+ :where(.${CSS_ROW}:last-child .${CSS_CELL}) {
2853
3332
  border-bottom-width: 0;
2854
3333
  }
2855
3334
 
2856
- :where(.tabela__row--body),
2857
- :where(.tabela__row--group) {
3335
+ :where(.${CSS_ROW}--body),
3336
+ :where(.${CSS_ROW}--group) {
2858
3337
  flex: 1;
2859
3338
  position: absolute;
2860
3339
  }
2861
3340
 
2862
- :where(.tabela__row--selected) {
3341
+ :where(.${CSS_ROW_SELECTED}) {
2863
3342
  background-color: var(--oui-blue-1);
2864
3343
  color: var(--oui-blue-9);
2865
3344
  }
2866
3345
 
2867
- :where(.tabela:has(.tabela__rowgroup--body:focus-visible) .tabela__row[data-active="true"]) {
3346
+ :where(.${CSS_WRAPPER}:has(.${CSS_ROWGROUP_BODY}:focus-visible) .${CSS_ROW}[data-active="true"]) {
2868
3347
  outline: 2px solid var(--oui-blue-6);
2869
3348
  outline-offset: 2px;
2870
3349
  }
2871
3350
 
2872
3351
  /** Cells */
2873
3352
 
2874
- :where(.tabela__cell),
2875
- :where(.tabela__heading) {
3353
+ :where(.${CSS_CELL}),
3354
+ :where(.${CSS_HEADING}) {
2876
3355
  padding: 0.5em;
2877
3356
  border-color: gray;
2878
3357
  border-style: solid;
@@ -2880,24 +3359,55 @@ const styling = `/** Table */
2880
3359
  line-height: 1;
2881
3360
  }
2882
3361
 
2883
- :where(.tabela__row .tabela__cell:last-child),
2884
- :where(.tabela__row .tabela__heading:last-child) {
3362
+ :where(.${CSS_WRAPPER} .${CSS_CELL}:last-child),
3363
+ :where(.${CSS_ROW} .${CSS_HEADING}:last-child) {
2885
3364
  flex: 1;
2886
3365
  border-right-width: 0;
2887
3366
  }
2888
3367
 
2889
- :where(.tabela__cell) {
3368
+ :where(.${CSS_CELL}) {
2890
3369
  overflow: hidden;
2891
3370
  text-overflow: ellipsis;
2892
3371
  white-space: nowrap;
2893
3372
  }
2894
3373
 
2895
- :where(.tabela__cell--footer) {
3374
+ :where(.${CSS_HEADING}) {
3375
+ display: flex;
3376
+ flex-flow: row nowrap;
3377
+ align-items: center;
3378
+ justify-content: space-between;
3379
+ gap: 0.5em;
3380
+ cursor: pointer;
3381
+ }
3382
+
3383
+ :where(.${CSS_HEADING_CONTENT}) {
3384
+ overflow: hidden;
3385
+ white-space: nowrap;
3386
+ text-overflow: ellipsis;
3387
+ }
3388
+
3389
+ :where(.${CSS_HEADING}[data-sort-direction] .${CSS_HEADING_SORTER})::after {
3390
+ width: 1em;
3391
+ height: 1em;
3392
+ display: inline-flex;
3393
+ font-size: .75em;
3394
+ font-weight: bold;
3395
+ }
3396
+
3397
+ :where(.${CSS_HEADING}[data-sort-direction="ascending"] .${CSS_HEADING_SORTER})::after {
3398
+ content: '\\21C8';
3399
+ }
3400
+
3401
+ :where(.${CSS_HEADING}[data-sort-direction="descending"] .${CSS_HEADING_SORTER})::after {
3402
+ content: '\\21CA';
3403
+ }
3404
+
3405
+ :where(.${CSS_CELL_FOOTER}) {
2896
3406
  border-top-width: 1px;
2897
3407
  border-bottom-width: 0;
2898
3408
  }
2899
3409
 
2900
- :where(.tabela__cell--group) {
3410
+ :where(.${CSS_CELL_GROUP}) {
2901
3411
  padding: 0;
2902
3412
  display: flex;
2903
3413
  flex-flow: row nowrap;
@@ -2905,18 +3415,18 @@ const styling = `/** Table */
2905
3415
  gap: 0.5em;
2906
3416
  }
2907
3417
 
2908
- :where(.tabela__cell--group .tabela__button) {
3418
+ :where(.${CSS_CELL_GROUP} .${CSS_BUTTON}) {
2909
3419
  margin: 0 0 0 .25rem;
2910
3420
  }
2911
3421
 
2912
3422
  /** Misc. */
2913
3423
 
2914
- :where(.tabela__button) {
3424
+ :where(.${CSS_BUTTON}) {
2915
3425
  font-size: .75rem;
2916
3426
  font-weight: bold;
2917
3427
  }
2918
3428
 
2919
- :where(.tabela__selection) {
3429
+ :where(.${CSS_SELECTION}) {
2920
3430
  background-color: color-mix(in oklch, var(--oui-blue-6), transparent);
2921
3431
  border: 1px solid var(--oui-blue-6);
2922
3432
  border-radius: .25rem;
@@ -2931,7 +3441,6 @@ var Tabela = class {
2931
3441
  #components;
2932
3442
  #element;
2933
3443
  #id = getId();
2934
- #table;
2935
3444
  #key;
2936
3445
  #managers = {
2937
3446
  column: void 0,
@@ -2946,37 +3455,37 @@ var Tabela = class {
2946
3455
  sort: void 0,
2947
3456
  style: void 0
2948
3457
  };
3458
+ #prefix = `tabela_${this.#id}_`;
2949
3459
  #state;
3460
+ #table;
2950
3461
  data;
3462
+ events;
2951
3463
  filter;
2952
3464
  group;
2953
3465
  selection;
2954
3466
  sort;
2955
- get key() {
2956
- return this.#key;
2957
- }
2958
3467
  constructor(element, options) {
2959
3468
  this.#element = element;
2960
3469
  element.innerHTML = "";
2961
- element.classList.add(CSS_TABELA);
3470
+ element.classList.add(CSS_WRAPPER);
2962
3471
  this.#table = createElement("div", {
2963
- className: CSS_TABELA_TABLE,
2964
- role: "table"
2965
- }, { "aria-label": options.label });
3472
+ className: CSS_TABLE,
3473
+ role: ROLE_TABLE
3474
+ }, { [ARIA_LABEL]: options.label });
2966
3475
  this.#key = options.key;
2967
- this.#components = {
2968
- body: new BodyComponent(),
2969
- footer: new FooterComponent(),
2970
- header: new HeaderComponent()
2971
- };
3476
+ this.#components = {};
2972
3477
  this.#state = {
2973
3478
  options,
2974
3479
  components: this.#components,
2975
3480
  element: this.#table,
2976
3481
  id: this.#id,
2977
3482
  key: this.#key,
2978
- managers: this.#managers
3483
+ managers: this.#managers,
3484
+ prefix: this.#prefix
2979
3485
  };
3486
+ this.#components.body = new BodyComponent(this.#state);
3487
+ this.#components.footer = new FooterComponent(this.#state);
3488
+ this.#components.header = new HeaderComponent(this.#state);
2980
3489
  this.#managers.column = new ColumnManager(this.#state);
2981
3490
  this.#managers.data = new DataManager(this.#state);
2982
3491
  this.#managers.event = new EventManager(this.#state);
@@ -2992,6 +3501,7 @@ var Tabela = class {
2992
3501
  element.append(this.#table);
2993
3502
  this.#managers.data.set(options.data);
2994
3503
  this.data = this.#managers.data.handlers;
3504
+ this.events = this.#managers.event.handlers;
2995
3505
  this.filter = this.#managers.filter.handlers;
2996
3506
  this.group = this.#managers.group.handlers;
2997
3507
  this.selection = this.#managers.selection.handlers;
@@ -3017,10 +3527,9 @@ var Tabela = class {
3017
3527
  managers.sort.destroy();
3018
3528
  element.innerHTML = "";
3019
3529
  table.innerHTML = "";
3020
- table.role = "";
3021
- element.classList.remove(CSS_TABELA);
3022
- table.removeAttribute("aria-label");
3023
- table.removeAttribute("role");
3530
+ element.classList.remove(CSS_WRAPPER);
3531
+ table.removeAttribute(ARIA_LABEL);
3532
+ table.removeAttribute(ATTRIBUTE_ROLE);
3024
3533
  this.#state.components = void 0;
3025
3534
  this.#state.managers = void 0;
3026
3535
  this.#state.element = void 0;