@oscarpalmer/tabela 0.10.0 → 0.12.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 (69) hide show
  1. package/dist/components/body.component.js +1 -0
  2. package/dist/components/column.component.js +4 -4
  3. package/dist/components/group.component.js +28 -0
  4. package/dist/components/row.component.js +11 -8
  5. package/dist/helpers/dom.helpers.js +1 -1
  6. package/dist/managers/column.manager.js +9 -8
  7. package/dist/managers/data.manager.js +95 -30
  8. package/dist/managers/event.manager.js +42 -23
  9. package/dist/managers/filter.manager.js +16 -10
  10. package/dist/managers/group.manager.js +46 -0
  11. package/dist/managers/navigation.manager.js +73 -0
  12. package/dist/managers/render.manager.js +61 -31
  13. package/dist/managers/row.manager.js +7 -7
  14. package/dist/managers/selection.manager.js +49 -46
  15. package/dist/managers/sort.manager.js +37 -9
  16. package/dist/models/group.model.js +0 -0
  17. package/dist/models/selection.model.js +0 -0
  18. package/dist/tabela.full.js +682 -591
  19. package/dist/tabela.js +31 -10
  20. package/package.json +1 -1
  21. package/src/components/body.component.ts +2 -0
  22. package/src/components/column.component.ts +6 -6
  23. package/src/components/group.component.ts +43 -0
  24. package/src/components/row.component.ts +14 -9
  25. package/src/helpers/dom.helpers.ts +3 -1
  26. package/src/managers/column.manager.ts +13 -15
  27. package/src/managers/data.manager.ts +176 -38
  28. package/src/managers/event.manager.ts +68 -41
  29. package/src/managers/filter.manager.ts +29 -20
  30. package/src/managers/group.manager.ts +79 -0
  31. package/src/managers/navigation.manager.ts +146 -0
  32. package/src/managers/render.manager.ts +84 -40
  33. package/src/managers/row.manager.ts +9 -14
  34. package/src/managers/selection.manager.ts +68 -67
  35. package/src/managers/sort.manager.ts +85 -22
  36. package/src/models/column.model.ts +2 -2
  37. package/src/models/data.model.ts +14 -3
  38. package/src/models/filter.model.ts +11 -3
  39. package/src/models/group.model.ts +4 -0
  40. package/src/models/render.model.ts +3 -1
  41. package/src/models/selection.model.ts +9 -0
  42. package/src/models/sort.model.ts +11 -3
  43. package/src/models/tabela.model.ts +14 -36
  44. package/src/models/tabela.options.ts +3 -2
  45. package/src/tabela.ts +43 -19
  46. package/types/components/column.component.d.ts +3 -3
  47. package/types/components/group.component.d.ts +14 -0
  48. package/types/components/row.component.d.ts +2 -2
  49. package/types/helpers/style.helper.d.ts +1 -1
  50. package/types/managers/column.manager.d.ts +6 -7
  51. package/types/managers/data.manager.d.ts +7 -6
  52. package/types/managers/event.manager.d.ts +3 -6
  53. package/types/managers/filter.manager.d.ts +11 -11
  54. package/types/managers/group.manager.d.ts +17 -0
  55. package/types/managers/navigation.manager.d.ts +10 -0
  56. package/types/managers/render.manager.d.ts +6 -7
  57. package/types/managers/row.manager.d.ts +4 -5
  58. package/types/managers/selection.manager.d.ts +12 -7
  59. package/types/managers/sort.manager.d.ts +11 -9
  60. package/types/models/column.model.d.ts +2 -2
  61. package/types/models/data.model.d.ts +13 -3
  62. package/types/models/filter.model.d.ts +10 -3
  63. package/types/models/group.model.d.ts +4 -0
  64. package/types/models/render.model.d.ts +2 -1
  65. package/types/models/selection.model.d.ts +8 -0
  66. package/types/models/sort.model.d.ts +10 -3
  67. package/types/models/tabela.model.d.ts +14 -33
  68. package/types/models/tabela.options.d.ts +3 -2
  69. package/types/tabela.d.ts +4 -1
@@ -318,7 +318,7 @@ new Set([
318
318
  * @param value Value to check
319
319
  * @returns `true` if the value is nullable or a whitespace-only string, otherwise `false`
320
320
  */
321
- function isNullableOrWhitespace(value) {
321
+ function isNullableOrWhitespace$1(value) {
322
322
  return value == null || EXPRESSION_WHITESPACE$1.test(getString$1(value));
323
323
  }
324
324
  var EXPRESSION_WHITESPACE$1 = /^\s*$/;
@@ -346,55 +346,12 @@ function setElementValues(element, first, second, third, callback) {
346
346
  }
347
347
  }
348
348
  function updateElementValue(element, key, value, set, remove, isBoolean, json) {
349
- if (isBoolean ? value == null : isNullableOrWhitespace(value)) remove.call(element, key);
349
+ if (isBoolean ? value == null : isNullableOrWhitespace$1(value)) remove.call(element, key);
350
350
  else set.call(element, key, json ? JSON.stringify(value) : String(value));
351
351
  }
352
- function badAttributeHandler(name, value) {
353
- if (typeof name !== "string" || name.trim().length === 0 || typeof value !== "string") return true;
354
- if (EXPRESSION_CLOBBERED_NAME.test(name) && (value in document || value in formElement) || EXPRESSION_EVENT_NAME.test(name)) return true;
355
- if (EXPRESSION_SKIP_NAME.test(name) || EXPRESSION_URI_VALUE.test(value) || isValidSourceAttribute(name, value)) return false;
356
- return EXPRESSION_DATA_OR_SCRIPT.test(value);
357
- }
358
- function booleanAttributeHandler(name, value) {
359
- if (typeof name !== "string" || name.trim().length === 0 || typeof value !== "string") return true;
360
- const normalizedName = name.toLowerCase();
361
- if (!booleanAttributesSet.has(normalizedName)) return false;
362
- const normalized = value.toLowerCase();
363
- return !(normalized.length === 0 || normalized === normalizedName);
364
- }
365
- function decodeAttribute(value) {
366
- textArea ??= document.createElement("textarea");
367
- textArea.innerHTML = value;
368
- return decodeURIComponent(textArea.value);
369
- }
370
- function handleAttribute(callback, decode, first, second) {
371
- let name;
372
- let value;
373
- if (isAttribute(first)) {
374
- name = first.name;
375
- value = String(first.value);
376
- } else if (typeof first === "string" && typeof second === "string") {
377
- name = first;
378
- value = second;
379
- }
380
- if (decode && value != null) value = decodeAttribute(value);
381
- return callback(name, value?.replace(EXPRESSION_WHITESPACE, ""));
382
- }
383
352
  function isAttribute(value) {
384
353
  return value instanceof Attr || isPlainObject$1(value) && typeof value.name === "string" && "value" in value;
385
354
  }
386
- function _isBadAttribute(first, second, decode) {
387
- return handleAttribute(badAttributeHandler, decode, first, second);
388
- }
389
- function _isEmptyNonBooleanAttribute(first, second, decode) {
390
- return handleAttribute((name, value) => name != null && value != null && !booleanAttributesSet.has(name) && value.trim().length === 0, decode, first, second);
391
- }
392
- function _isInvalidBooleanAttribute(first, second, decode) {
393
- return handleAttribute(booleanAttributeHandler, decode, first, second);
394
- }
395
- function isValidSourceAttribute(name, value) {
396
- return EXPRESSION_SOURCE_NAME.test(name) && EXPRESSION_SOURCE_VALUE.test(value);
397
- }
398
355
  function updateAttribute(element, name, value, dispatch) {
399
356
  const normalizedName = name.toLowerCase();
400
357
  const isBoolean = booleanAttributesSet.has(normalizedName);
@@ -408,14 +365,6 @@ function updateProperty(element, name, value, dispatch) {
408
365
  const event = dispatch !== false && elementEvents[element.tagName]?.[name];
409
366
  if (typeof event === "string") element.dispatchEvent(new Event(event, { bubbles: true }));
410
367
  }
411
- var EXPRESSION_CLOBBERED_NAME = /^(id|name)$/i;
412
- var EXPRESSION_DATA_OR_SCRIPT = /^(?:data|\w+script):/i;
413
- var EXPRESSION_EVENT_NAME = /^on/i;
414
- var EXPRESSION_SKIP_NAME = /^(aria-[-\w]+|data-[-\w.\u00B7-\uFFFF]+)$/i;
415
- var EXPRESSION_SOURCE_NAME = /^src$/i;
416
- var EXPRESSION_SOURCE_VALUE = /^data:/i;
417
- var EXPRESSION_URI_VALUE = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i;
418
- var EXPRESSION_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g;
419
368
  /**
420
369
  * List of boolean attributes
421
370
  */
@@ -455,8 +404,7 @@ var elementEvents = {
455
404
  SELECT: { value: "change" },
456
405
  TEXTAREA: { value: "input" }
457
406
  };
458
- var formElement = document.createElement("form");
459
- var textArea;
407
+ document.createElement("form");
460
408
  function setAttribute(element, first, second, third) {
461
409
  setElementValue(element, first, second, third, updateAttribute);
462
410
  }
@@ -560,7 +508,7 @@ function createRow() {
560
508
  return createElement("div", {
561
509
  className: "tabela__row",
562
510
  role: "row"
563
- }, {}, {});
511
+ }, {}, { height: "32px" });
564
512
  }
565
513
  function createFaker() {
566
514
  return createElement("div", { className: "tabela__faker" }, {}, {});
@@ -575,6 +523,7 @@ var BodyComponent = class {
575
523
  this.elements.group = group;
576
524
  group.className += " tabela__rowgroup--body";
577
525
  group.tabIndex = 0;
526
+ group.setAttribute("data-event", "body");
578
527
  group.append(this.elements.faker);
579
528
  }
580
529
  destroy() {
@@ -636,13 +585,13 @@ var HeaderComponent = class {
636
585
  var ColumnComponent = class {
637
586
  elements;
638
587
  options;
639
- constructor(options) {
640
- const width = Number.parseInt(getComputedStyle(document.body).fontSize, 10) * (options.width ?? options.title.length * 1.5);
588
+ constructor(column) {
589
+ const width = Number.parseInt(getComputedStyle(document.body).fontSize, 10) * (column.width ?? column.title.length * 1.5);
641
590
  this.options = {
642
- ...options,
591
+ ...column,
643
592
  width
644
593
  };
645
- this.elements = createHeading(options.field, options.title, width);
594
+ this.elements = createHeading(this.options.field, this.options.title, width);
646
595
  }
647
596
  destroy() {
648
597
  this.elements.content.remove();
@@ -674,18 +623,19 @@ function createHeading(field, title, width) {
674
623
  }
675
624
  var ColumnManager = class {
676
625
  items = [];
677
- constructor(managers, components, columns) {
678
- this.managers = managers;
679
- this.components = components;
680
- this.set(columns);
626
+ constructor(state) {
627
+ this.state = state;
628
+ this.set(state.options.columns);
681
629
  }
682
630
  destroy() {
683
631
  const { length } = this.items;
684
632
  for (let index = 0; index < length; index += 1) this.items[index].destroy();
685
- this.items.length = 0;
633
+ this.items = void 0;
634
+ this.state = void 0;
686
635
  }
687
636
  remove(value) {
688
- const { components, items, managers } = this;
637
+ const { items, state } = this;
638
+ const { components, managers } = state;
689
639
  const fields = (Array.isArray(value) ? value : [value]).filter((item) => typeof item === "string");
690
640
  const { length } = fields;
691
641
  if (length === 0) return;
@@ -701,8 +651,8 @@ var ColumnManager = class {
701
651
  managers.render.removeCells(fields);
702
652
  }
703
653
  set(columns) {
704
- const { components, items } = this;
705
- const { footer, header } = components;
654
+ const { items, state } = this;
655
+ const { footer, header } = state.components;
706
656
  items.splice(0, items.length, ...columns.map((column) => new ColumnComponent(column)));
707
657
  header.update(items);
708
658
  footer.update(items);
@@ -862,35 +812,8 @@ function compact(array, strict) {
862
812
  }
863
813
  return compacted;
864
814
  }
865
- function insertChunkedValues(type, array, items, start, deleteCount) {
866
- const actualDeleteCount = deleteCount < 0 ? 0 : deleteCount;
867
- const actualStart = Math.min(Math.max(0, start), array.length);
868
- const chunked = chunk(items);
869
- const lastIndex = chunked.length - 1;
870
- let index = Number(chunked.length);
871
- let returned;
872
- while (index > 0) {
873
- index -= 1;
874
- const spliced = array.splice(actualStart, index === lastIndex ? actualDeleteCount : 0, ...chunked[index]);
875
- if (returned == null) returned = spliced;
876
- else returned.push(...spliced);
877
- }
878
- if (type === "insert") return array;
879
- return type === "splice" ? returned : array.length;
880
- }
881
- function insertValues(type, array, items, start, deleteCount) {
882
- const spliceArray = type === "insert" || type === "splice";
883
- if (!Array.isArray(array) || typeof start !== "number" || !Array.isArray(items) || items.length === 0) return spliceArray ? [] : 0;
884
- return insertChunkedValues(type, array, items, start, spliceArray ? deleteCount : 0);
885
- }
886
- /**
887
- * Push items into an array _(at the end)_
888
- * @param array Original array
889
- * @param pushed Pushed items
890
- * @returns New length of the array
891
- */
892
- function push(array, pushed) {
893
- return insertValues("push", array, pushed, array.length, 0);
815
+ function select(array, ...parameters) {
816
+ return findValues("all", array, parameters, parameters.pop()).matched;
894
817
  }
895
818
  function aggregate(type, array, key) {
896
819
  const length = Array.isArray(array) ? array.length : 0;
@@ -1157,6 +1080,181 @@ toMap.arrays = toMapArrays;
1157
1080
  function toMapArrays(array, first, second) {
1158
1081
  return getMapValues(array, first, second, true);
1159
1082
  }
1083
+ function groupValues(array, key, value, arrays) {
1084
+ if (!Array.isArray(array) || array.length === 0) return {};
1085
+ const { length } = array;
1086
+ const callbacks = getArrayCallbacks(void 0, key, value);
1087
+ const record = {};
1088
+ for (let index = 0; index < length; index += 1) {
1089
+ const item = array[index];
1090
+ const keyed = callbacks?.keyed?.(item, index, array) ?? index;
1091
+ const valued = callbacks?.value?.(item, index, array) ?? item;
1092
+ if (arrays) {
1093
+ const existing = record[keyed];
1094
+ if (existing == null) record[keyed] = [valued];
1095
+ else existing.push(valued);
1096
+ } else record[keyed] = valued;
1097
+ }
1098
+ return record;
1099
+ }
1100
+ function toRecord(array, first, second) {
1101
+ return groupValues(array, first, second, false);
1102
+ }
1103
+ toRecord.arrays = toRecordArrays;
1104
+ function toRecordArrays(array, first, second) {
1105
+ return groupValues(array, first, second, true);
1106
+ }
1107
+ var GroupComponent = class {
1108
+ element;
1109
+ expanded = true;
1110
+ filtered = 0;
1111
+ selected = 0;
1112
+ total = 0;
1113
+ constructor(key, label, value) {
1114
+ this.key = key;
1115
+ this.label = label;
1116
+ this.value = value;
1117
+ }
1118
+ };
1119
+ function renderGroup(state, component) {
1120
+ component.element ??= createElement("div", {
1121
+ className: "tabela__row tabela__row--group",
1122
+ innerHTML: `<div class="tabela__cell tabela__cell--group" role="cell">
1123
+ <button class="tabela__button tabela__button--group" data-event="group" data-key="${component.key}" type="button">
1124
+ <span aria-hidden="true"></span>
1125
+ <span>Open/close</span>
1126
+ </button>
1127
+ <p>${component.label}</p>
1128
+ </div>`,
1129
+ role: "row"
1130
+ }, {}, { height: `${state.options.rowHeight}px` });
1131
+ }
1132
+ var SortManager = class {
1133
+ handlers = Object.freeze({
1134
+ add: (field, direction) => this.add(field, direction),
1135
+ flip: (field) => this.flip(field),
1136
+ clear: () => this.clear(),
1137
+ remove: (field) => this.remove(field),
1138
+ set: (items) => this.set(items)
1139
+ });
1140
+ items = [];
1141
+ constructor(state) {
1142
+ this.state = state;
1143
+ }
1144
+ add(field, direction) {
1145
+ if (this.items.findIndex((item) => item.key === field) > -1) return;
1146
+ this.items.push({
1147
+ key: field,
1148
+ direction: direction ?? "ascending"
1149
+ });
1150
+ this.sort();
1151
+ }
1152
+ addOrSet(event, field) {
1153
+ if (event.ctrlKey || event.metaKey) this.add(field);
1154
+ else this.set([{
1155
+ field,
1156
+ direction: "ascending"
1157
+ }]);
1158
+ }
1159
+ clear() {
1160
+ if (this.items.length > 0) {
1161
+ this.items.length = 0;
1162
+ this.sort();
1163
+ }
1164
+ }
1165
+ destroy() {
1166
+ this.handlers = void 0;
1167
+ this.items = void 0;
1168
+ this.state = void 0;
1169
+ }
1170
+ flip(field) {
1171
+ const item = this.items.find((item) => item.key === field);
1172
+ if (item == null) return;
1173
+ item.direction = item.direction === "ascending" ? "descending" : "ascending";
1174
+ this.sort();
1175
+ }
1176
+ remove(field) {
1177
+ const index = this.items.findIndex((item) => item.key === field);
1178
+ if (index > -1) {
1179
+ this.items.splice(index, 1);
1180
+ this.sort();
1181
+ }
1182
+ }
1183
+ removeOrClear(event, field) {
1184
+ if (event.ctrlKey || event.metaKey) this.remove(field);
1185
+ else this.clear();
1186
+ }
1187
+ set(items) {
1188
+ this.items.splice(0, this.items.length, ...items.map((item) => ({
1189
+ key: item.field,
1190
+ direction: item.direction
1191
+ })));
1192
+ this.sort();
1193
+ }
1194
+ sort() {
1195
+ const { items, state } = this;
1196
+ const { length } = state.managers.column.items;
1197
+ for (let index = 0; index < length; index += 1) {
1198
+ const column = state.managers.column.items[index];
1199
+ const sorterIndex = items.findIndex((item) => item.key === column.options.field);
1200
+ const sorterItem = items[sorterIndex];
1201
+ setAttributes(column.elements.wrapper, {
1202
+ "aria-sort": sorterItem == null ? "none" : items.length > 1 ? "other" : sorterItem.direction,
1203
+ "data-sort-direction": sorterItem == null ? void 0 : sorterItem.direction
1204
+ });
1205
+ setAttribute(column.elements.sorter, "data-sort-position", sorterIndex > -1 && items.length > 1 ? sorterIndex + 1 : void 0);
1206
+ }
1207
+ state.managers.data.values.keys.active = items.length === 0 ? void 0 : getSortedKeys(state, items);
1208
+ state.managers.render.update(true, true);
1209
+ }
1210
+ toggle(event, field, direction) {
1211
+ switch (direction) {
1212
+ case "ascending":
1213
+ this.flip(field);
1214
+ return;
1215
+ case "descending":
1216
+ this.removeOrClear(event, field);
1217
+ return;
1218
+ default:
1219
+ this.addOrSet(event, field);
1220
+ return;
1221
+ }
1222
+ }
1223
+ };
1224
+ function getSortedKeys(state, sorters) {
1225
+ const data = state.managers.data.values.keys.active?.map((key) => key instanceof GroupComponent ? key : state.managers.data.values.objects.mapped.get(key)) ?? state.managers.data.values.objects.array.slice();
1226
+ if (!state.managers.group.enabled) return sort(data, sorters).map((item) => item[state.key]);
1227
+ return sortWithGroups(state, data, sorters).map((item) => item instanceof GroupComponent ? item : item[state.key]);
1228
+ }
1229
+ function sortWithGroups(state, data, sorters) {
1230
+ const { length } = sorters;
1231
+ return data.sort((first, second) => {
1232
+ const firstValue = first instanceof GroupComponent ? first.value : first[state.managers.group.field];
1233
+ const secondValue = second instanceof GroupComponent ? second.value : second[state.managers.group.field];
1234
+ const firstOrder = state.managers.group.order[firstValue];
1235
+ const secondOrder = state.managers.group.order[secondValue];
1236
+ const groupComparison = compare(firstOrder, secondOrder);
1237
+ if (groupComparison !== 0) return groupComparison;
1238
+ const firstIsGroup = first instanceof GroupComponent;
1239
+ const secondIsGroup = second instanceof GroupComponent;
1240
+ if (firstIsGroup || secondIsGroup) return firstIsGroup && secondIsGroup ? 0 : firstIsGroup ? -1 : 1;
1241
+ for (let index = 0; index < length; index += 1) {
1242
+ const sorter = sorters[index];
1243
+ const comparison = compare(first[sorter.key], second[sorter.key]);
1244
+ if (comparison !== 0) return comparison * (sorter.direction === "ascending" ? 1 : -1);
1245
+ }
1246
+ return 0;
1247
+ });
1248
+ }
1249
+ /**
1250
+ * Is the value `undefined`, `null`, or a whitespace-only string?
1251
+ * @param value Value to check
1252
+ * @returns `true` if the value is nullable or a whitespace-only string, otherwise `false`
1253
+ */
1254
+ function isNullableOrWhitespace(value) {
1255
+ return value == null || EXPRESSION_WHITESPACE.test(getString(value));
1256
+ }
1257
+ var EXPRESSION_WHITESPACE = /^\s*$/;
1160
1258
  var DataManager = class {
1161
1259
  handlers = Object.freeze({
1162
1260
  add: (data) => void this.add(data, true),
@@ -1173,19 +1271,41 @@ var DataManager = class {
1173
1271
  array: []
1174
1272
  }
1175
1273
  };
1274
+ get keys() {
1275
+ return this.values.keys.active ?? this.values.keys.original;
1276
+ }
1176
1277
  get size() {
1177
- return this.values.keys.active?.length ?? this.values.keys.original.length;
1278
+ return this.keys.length;
1178
1279
  }
1179
- constructor(managers, components, field) {
1180
- this.managers = managers;
1181
- this.components = components;
1182
- this.field = field;
1280
+ constructor(state) {
1281
+ this.state = state;
1183
1282
  }
1184
1283
  async add(data, render) {
1185
- const { field, values } = this;
1186
- push(values.objects.array, data);
1187
- values.objects.mapped = toMap(values.objects.array, field);
1188
- if (render) this.render();
1284
+ const { state, values } = this;
1285
+ const { length } = data;
1286
+ const updates = [];
1287
+ for (let index = 0; index < length; index += 1) {
1288
+ const item = data[index];
1289
+ const key = item[state.key];
1290
+ if (values.objects.mapped.has(key)) {
1291
+ updates.push(item);
1292
+ continue;
1293
+ }
1294
+ values.objects.array.push(item);
1295
+ values.objects.mapped.set(key, item);
1296
+ if (!state.managers.group.enabled) continue;
1297
+ const groupKey = item[state.managers.group.field];
1298
+ let group = state.managers.group.get(groupKey);
1299
+ if (group == null) {
1300
+ group = new GroupComponent(String(groupKey), String(groupKey), groupKey);
1301
+ values.objects.array.push(group);
1302
+ state.managers.group.add(group);
1303
+ }
1304
+ if (!group.expanded) state.managers.group.collapsed.add(key);
1305
+ group.total += 1;
1306
+ }
1307
+ if (updates.length > 0) this.update(updates);
1308
+ else if (render) this.render();
1189
1309
  }
1190
1310
  clear() {
1191
1311
  if (this.values.objects.array.length > 0) this.set([]);
@@ -1197,55 +1317,95 @@ var DataManager = class {
1197
1317
  values.keys.original.length = 0;
1198
1318
  values.objects.array.length = 0;
1199
1319
  this.handlers = void 0;
1320
+ this.state = void 0;
1321
+ this.values = void 0;
1200
1322
  }
1201
1323
  get(active) {
1202
1324
  const { values } = this;
1203
- return active ?? false ? values.keys.active?.map((key) => values.objects.mapped.get(key)) ?? [] : values.objects.array;
1325
+ return active ?? false ? select(values.keys.active ?? [], (key) => !(key instanceof GroupComponent), (key) => values.objects.mapped.get(key)) : values.objects.array.filter((item) => !(item instanceof GroupComponent));
1326
+ }
1327
+ getIndex(key) {
1328
+ return this.keys.indexOf(key);
1204
1329
  }
1205
1330
  async remove(items, render) {
1206
- const { field, managers, values } = this;
1207
- const keys = items.map((value) => isPlainObject(value) ? value[field] : value).filter((key) => values.objects.mapped.has(key));
1331
+ const { state, values } = this;
1332
+ const keys = items.map((value) => isPlainObject(value) ? value[state.key] : value).filter((key) => values.objects.mapped.has(key));
1208
1333
  const { length } = keys;
1209
1334
  if (length === 0) return;
1210
1335
  for (let keyIndex = 0; keyIndex < length; keyIndex += 1) {
1211
1336
  const key = keys[keyIndex];
1212
1337
  values.objects.mapped.delete(key);
1213
- const arrayIndex = values.objects.array.findIndex((object) => object[field] === key);
1214
- if (arrayIndex > -1) values.objects.array.splice(arrayIndex, 1);
1338
+ const arrayIndex = values.objects.array.findIndex((item) => !(item instanceof GroupComponent) && item[state.key] === key);
1339
+ let item;
1340
+ if (arrayIndex > -1) [item] = values.objects.array.splice(arrayIndex, 1);
1215
1341
  values.keys.original.splice(values.keys.original.indexOf(key), 1);
1216
- managers.row.remove(key);
1342
+ state.managers.row.remove(key);
1343
+ if (!state.managers.group.enabled || item == null) continue;
1344
+ state.managers.group.collapsed.delete(key);
1345
+ const groupKey = item[state.managers.group.field];
1346
+ const group = state.managers.group.get(groupKey);
1347
+ if (group == null) continue;
1348
+ group.total -= 1;
1349
+ if (group.total > 0) continue;
1350
+ const groupIndex = values.objects.array.findIndex((item) => item instanceof GroupComponent && item.value === groupKey);
1351
+ if (groupIndex > -1) values.objects.array.splice(groupIndex, 1);
1352
+ state.managers.group.remove(group);
1217
1353
  }
1218
1354
  if (render) this.render();
1219
1355
  }
1220
1356
  render() {
1221
- const { field, managers, values } = this;
1222
- values.keys.original = sort(values.objects.array.map((item) => item[field]));
1223
- if (Object.keys(managers.filter.items).length > 0) managers.filter.filter();
1224
- else if (managers.sort.items.length > 0) managers.sort.sort();
1225
- else managers.render.update(true);
1357
+ const { state, values } = this;
1358
+ if (state.managers.group.enabled) sortWithGroups(state, values.objects.array, [{
1359
+ direction: "ascending",
1360
+ key: state.key
1361
+ }]);
1362
+ else sort(values.objects.array, [{
1363
+ direction: "ascending",
1364
+ key: state.key
1365
+ }]);
1366
+ values.keys.original = values.objects.array.map((item) => item instanceof GroupComponent ? item : item[state.key]);
1367
+ values.objects.mapped = toMap(values.objects.array.filter((item) => !(item instanceof GroupComponent)), (item) => item[state.key]);
1368
+ if (Object.keys(state.managers.filter.items).length > 0) state.managers.filter.filter();
1369
+ else if (state.managers.sort.items.length > 0) state.managers.sort.sort();
1370
+ else state.managers.render.update(true, true);
1226
1371
  }
1227
1372
  set(data) {
1228
- const { field, values } = this;
1229
- values.objects.mapped = toMap(data, field);
1230
- values.objects.array = data;
1373
+ const { state, values } = this;
1374
+ const array = data.slice();
1375
+ if (state.managers.group.enabled) {
1376
+ const grouped = toRecord.arrays(data, state.managers.group.field);
1377
+ const entries = Object.entries(grouped);
1378
+ const { length } = entries;
1379
+ const groups = [];
1380
+ for (let index = 0; index < length; index += 1) {
1381
+ const [value, items] = entries[index];
1382
+ const key = String(value);
1383
+ const group = new GroupComponent(key, key, value);
1384
+ group.total = items.length;
1385
+ groups.push(group);
1386
+ array.push(group);
1387
+ }
1388
+ state.managers.group.set(groups);
1389
+ }
1390
+ values.objects.array = array;
1231
1391
  this.render();
1232
1392
  }
1233
1393
  async synchronize(data, remove) {
1234
- const { field, values } = this;
1394
+ const { state, values } = this;
1235
1395
  const add = [];
1236
1396
  const updated = [];
1237
1397
  const keys = /* @__PURE__ */ new Set([]);
1238
1398
  const { length } = data;
1239
1399
  for (let index = 0; index < length; index += 1) {
1240
1400
  const object = data[index];
1241
- const key = object[field];
1401
+ const key = object[state.key];
1242
1402
  if (values.objects.mapped.has(key)) updated.push(object);
1243
1403
  else add.push(object);
1244
1404
  keys.add(key);
1245
1405
  }
1246
1406
  if (keys.size === 0) return;
1247
1407
  if (remove ?? false) {
1248
- const toRemove = values.keys.original.filter((key) => !keys.has(key));
1408
+ const toRemove = values.keys.original.filter((key) => !(key instanceof GroupComponent) && !keys.has(key));
1249
1409
  if (toRemove.length > 0) await this.remove(toRemove, false);
1250
1410
  }
1251
1411
  await this.update(updated);
@@ -1253,18 +1413,18 @@ var DataManager = class {
1253
1413
  if (add.length > 0 || (remove ?? false)) this.render();
1254
1414
  }
1255
1415
  async update(data) {
1256
- const { field, managers, values } = this;
1416
+ const { state, values } = this;
1257
1417
  const { length } = data;
1258
1418
  for (let index = 0; index < length; index += 1) {
1259
1419
  const object = data[index];
1260
- const key = object[field];
1420
+ const key = object[state.key];
1261
1421
  const value = values.objects.mapped.get(key);
1262
1422
  if (value != null) {
1263
1423
  values.objects.mapped.set(key, {
1264
1424
  ...value,
1265
1425
  ...object
1266
1426
  });
1267
- managers.row.update(key);
1427
+ state.managers.row.update(key);
1268
1428
  }
1269
1429
  }
1270
1430
  }
@@ -1413,203 +1573,56 @@ function getElement(origin) {
1413
1573
  if (origin instanceof Element) return origin;
1414
1574
  return origin instanceof Event && origin.target instanceof Element ? origin.target : void 0;
1415
1575
  }
1416
- function isInert(item) {
1417
- return (item.element.inert ?? false) || EXPRESSION_TRUEISH.test(item.element.getAttribute(ATTRIBUTE_INERT)) || item.element.parentElement != null && isInert({
1418
- element: item.element.parentElement,
1419
- tabIndex: TABINDEX_DEFAULT
1420
- });
1421
- }
1422
- var ATTRIBUTE_INERT = "inert";
1423
- var EXPRESSION_TRUEISH = /^(|true)$/i;
1424
- [
1425
- "[contenteditable]:not([contenteditable=\"false\"])",
1426
- "[tabindex]:not(slot)",
1427
- "a[href]",
1428
- "audio[controls]",
1429
- "button",
1430
- "details",
1431
- "details > summary:first-of-type",
1432
- "input",
1433
- "select",
1434
- "textarea",
1435
- "video[controls]"
1436
- ].map((selector) => `${selector}:not([inert])`).join(",");
1437
- var TABINDEX_DEFAULT = -1;
1438
- function handleElement(element, depth) {
1439
- if (depth === 0) {
1440
- const removable = element.querySelectorAll(REMOVE_SELECTOR);
1441
- for (const item of removable) item.remove();
1442
- }
1443
- sanitizeAttributes(element, [...element.attributes]);
1444
- }
1445
- /**
1446
- * Is the element clobbered?
1447
- *
1448
- * Thanks, DOMPurify _(https://github.com/cure53/DOMPurify)_
1449
- */
1450
- function isClobbered(value) {
1451
- return value instanceof HTMLFormElement && (typeof value.nodeName !== "string" || typeof value.textContent !== "string" || typeof value.removeChild !== "function" || !(value.attributes instanceof NamedNodeMap) || typeof value.removeAttribute !== "function" || typeof value.setAttribute !== "function" || typeof value.namespaceURI !== "string" || typeof value.insertBefore !== "function" || typeof value.hasChildNodes !== "function");
1452
- }
1453
- function removeNode(node) {
1454
- if (typeof node.remove === "function") node.remove();
1455
- }
1456
- function sanitizeAttributes(element, attributes) {
1457
- const { length } = attributes;
1458
- for (let index = 0; index < length; index += 1) {
1459
- const { name, value } = attributes[index];
1460
- if (_isBadAttribute(name, value, false) || _isEmptyNonBooleanAttribute(name, value, false)) element.removeAttribute(name);
1461
- else if (_isInvalidBooleanAttribute(name, value, false)) setAttribute(element, name, true);
1462
- }
1463
- }
1464
- function sanitizeNodes(nodes, depth) {
1465
- const actual = nodes.filter((node) => node instanceof Node);
1466
- let { length } = nodes;
1467
- for (let index = 0; index < length; index += 1) {
1468
- const node = actual[index];
1469
- let remove = isClobbered(node);
1470
- if (!remove) switch (node.nodeType) {
1471
- case Node.ELEMENT_NODE:
1472
- handleElement(node, depth);
1473
- break;
1474
- case Node.COMMENT_NODE:
1475
- remove = COMMENT_HARMFUL.test(node.data);
1476
- break;
1477
- case Node.DOCUMENT_TYPE_NODE:
1478
- case Node.PROCESSING_INSTRUCTION_NODE:
1479
- remove = true;
1480
- break;
1481
- }
1482
- if (remove) {
1483
- removeNode(node);
1484
- actual.splice(index, 1);
1485
- index -= 1;
1486
- length -= 1;
1487
- continue;
1488
- }
1489
- if (node.hasChildNodes()) sanitizeNodes([...node.childNodes], depth + 1);
1490
- }
1491
- return nodes;
1492
- }
1493
- var COMMENT_HARMFUL = /<[/\w]/g;
1494
- var REMOVE_SELECTOR = "script, toretto-temporary";
1495
- function createHtml(value) {
1496
- const parsed = getParser().parseFromString(getHtml(value), PARSE_TYPE_HTML);
1497
- parsed.body.normalize();
1498
- sanitizeNodes([parsed.body], 0);
1499
- return parsed.body.innerHTML;
1500
- }
1501
- function createTemplate(value, options) {
1502
- const template = document.createElement(TEMPLATE_TAG);
1503
- template.innerHTML = createHtml(value);
1504
- if (typeof value === "string" && options.cache) templates[value] = template;
1505
- return template;
1506
- }
1507
- function getHtml(value) {
1508
- return `${TEMPORARY_ELEMENT}${typeof value === "string" ? value : value.innerHTML}${TEMPORARY_ELEMENT}`;
1509
- }
1510
- function getNodes(value, options) {
1511
- if (typeof value !== "string" && !(value instanceof HTMLTemplateElement)) return [];
1512
- const template = getTemplate(value, options);
1513
- return template == null ? [] : [...template.content.cloneNode(true).childNodes];
1514
- }
1515
- function getOptions(input) {
1516
- const options = isPlainObject$1(input) ? input : {};
1517
- options.cache = typeof options.cache === "boolean" ? options.cache : true;
1518
- return options;
1519
- }
1520
- function getParser() {
1521
- parser ??= new DOMParser();
1522
- return parser;
1523
- }
1524
- function getTemplate(value, options) {
1525
- if (value instanceof HTMLTemplateElement) return createTemplate(value, options);
1526
- if (value.trim().length === 0) return;
1527
- let template = templates[value];
1528
- if (template != null) return template;
1529
- const element = EXPRESSION_ID.test(value) ? document.querySelector(`#${value}`) : null;
1530
- return createTemplate(element instanceof HTMLTemplateElement ? element : value, options);
1531
- }
1532
- var html = ((value, options) => {
1533
- return getNodes(value, getOptions(options));
1534
- });
1535
- html.clear = () => {
1536
- templates = {};
1537
- };
1538
- html.remove = (template) => {
1539
- if (typeof template !== "string" || templates[template] == null) return;
1540
- const keys = Object.keys(templates);
1541
- const { length } = keys;
1542
- const updated = {};
1543
- for (let index = 0; index < length; index += 1) {
1544
- const key = keys[index];
1545
- if (key !== template) updated[key] = templates[key];
1546
- }
1547
- templates = updated;
1548
- };
1549
- var EXPRESSION_ID = /^[a-z][\w-]*$/i;
1550
- var PARSE_TYPE_HTML = "text/html";
1551
- var TEMPLATE_TAG = "template";
1552
- var TEMPORARY_ELEMENT = "<toretto-temporary></toretto-temporary>";
1553
- var parser;
1554
- var templates = {};
1555
- function getSupport() {
1556
- if (window == null || navigator == null) return false;
1557
- if ("matchMedia" in window) {
1558
- const media = matchMedia?.("(pointer: coarse)");
1559
- if (typeof media?.matches === "boolean" && media.matches) return true;
1560
- }
1561
- if ("ontouchstart" in window) return true;
1562
- if (typeof navigator.maxTouchPoints === "number" && navigator.maxTouchPoints > 0) return true;
1563
- if (typeof navigator.msMaxTouchPoints === "number" && navigator.msMaxTouchPoints > 0) return true;
1564
- return false;
1565
- }
1566
- (() => {
1567
- let support = getSupport();
1568
- const instance = Object.create({
1569
- get() {
1570
- return support;
1571
- },
1572
- update() {
1573
- support = getSupport();
1574
- return support;
1575
- }
1576
- });
1577
- Object.defineProperty(instance, "value", { get() {
1578
- return support;
1579
- } });
1580
- return instance;
1581
- })();
1582
1576
  var EventManager = class {
1583
- listener;
1584
- constructor(element, managers) {
1585
- this.managers = managers;
1586
- this.listener = on(element, "click", (event) => {
1587
- this.onClick(event);
1588
- }, { passive: false });
1577
+ constructor(state) {
1578
+ this.state = state;
1579
+ mapped$1.set(state.element, this);
1589
1580
  }
1590
1581
  destroy() {
1591
- this.listener();
1592
- }
1593
- onClick(event) {
1594
- const target = findAncestor(event, "[data-event]");
1595
- if (!(target instanceof HTMLElement)) return;
1596
- switch (target?.getAttribute("data-event")) {
1597
- case "heading":
1598
- this.onSort(event, target);
1599
- break;
1600
- case "row":
1601
- this.managers.selection.handle(event, target);
1602
- break;
1603
- default: break;
1604
- }
1582
+ mapped$1.delete(this.state.element);
1583
+ this.state = void 0;
1605
1584
  }
1606
1585
  onSort(event, target) {
1607
- const { managers } = this;
1608
1586
  const direction = target.getAttribute("data-sort-direction");
1609
1587
  const field = target.getAttribute("data-field");
1610
- if (field != null) managers.sort.toggle(event, field, direction);
1588
+ if (field != null) this.state.managers.sort.toggle(event, field, direction);
1611
1589
  }
1612
1590
  };
1591
+ function onClick(event) {
1592
+ const target = findAncestor(event, "[data-event]");
1593
+ const table = findAncestor(event, ".tabela");
1594
+ if (!(target instanceof HTMLElement) || !(table instanceof HTMLElement)) return;
1595
+ const manager = mapped$1.get(table);
1596
+ if (manager == null) return;
1597
+ switch (target?.getAttribute("data-event")) {
1598
+ case "group":
1599
+ manager.state.managers.group.handle(target);
1600
+ break;
1601
+ case "heading":
1602
+ manager.onSort(event, target);
1603
+ break;
1604
+ case "row":
1605
+ manager.state.managers.selection.handle(event, target);
1606
+ break;
1607
+ default: break;
1608
+ }
1609
+ }
1610
+ function onKeydown(event) {
1611
+ const target = findAncestor(event, "[data-event]");
1612
+ const table = findAncestor(event, ".tabela");
1613
+ if (!(target instanceof HTMLElement) || !(table instanceof HTMLElement)) return;
1614
+ const manager = mapped$1.get(table);
1615
+ if (manager == null) return;
1616
+ switch (target?.getAttribute("data-event")) {
1617
+ case "body":
1618
+ manager.state.managers.navigation.handle(event);
1619
+ break;
1620
+ default: break;
1621
+ }
1622
+ }
1623
+ const mapped$1 = /* @__PURE__ */ new WeakMap();
1624
+ on(document, "click", onClick);
1625
+ on(document, "keydown", onKeydown, { passive: false });
1613
1626
  /**
1614
1627
  * Clamp a number between a minimum and maximum value
1615
1628
  * @param value Value to clamp
@@ -2014,8 +2027,8 @@ var FilterManager = class {
2014
2027
  set: (items) => this.set(items)
2015
2028
  });
2016
2029
  items = {};
2017
- constructor(managers) {
2018
- this.managers = managers;
2030
+ constructor(state) {
2031
+ this.state = state;
2019
2032
  }
2020
2033
  add(item) {
2021
2034
  if (this.items[item.field] == null) this.items[item.field] = [];
@@ -2031,16 +2044,21 @@ var FilterManager = class {
2031
2044
  }
2032
2045
  destroy() {
2033
2046
  this.handlers = void 0;
2034
- this.items = {};
2047
+ this.items = void 0;
2048
+ this.state = void 0;
2035
2049
  }
2036
2050
  filter() {
2037
- const { managers } = this;
2051
+ const { state } = this;
2038
2052
  const filtered = [];
2039
2053
  const filters = Object.entries(this.items);
2040
- const keysLength = managers.data.values.keys.original.length;
2054
+ const keysLength = state.managers.data.values.keys.original.length;
2041
2055
  rowLoop: for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
2042
- const key = managers.data.values.keys.original[keyIndex];
2043
- const row = managers.data.values.objects.mapped.get(key);
2056
+ const key = state.managers.data.values.keys.original[keyIndex];
2057
+ if (key instanceof GroupComponent) {
2058
+ filtered.push(key);
2059
+ continue;
2060
+ }
2061
+ const row = state.managers.data.values.objects.mapped.get(key);
2044
2062
  if (row == null) continue;
2045
2063
  filterLoop: for (let filterIndex = 0; filterIndex < filters.length; filterIndex += 1) {
2046
2064
  const [field, items] = filters[filterIndex];
@@ -2053,9 +2071,9 @@ var FilterManager = class {
2053
2071
  }
2054
2072
  filtered.push(key);
2055
2073
  }
2056
- managers.data.values.keys.active = filtered;
2057
- if (managers.sort.items.length > 0) managers.sort.sort();
2058
- else managers.render.update(true, true);
2074
+ state.managers.data.values.keys.active = filtered;
2075
+ if (state.managers.sort.items.length > 0) state.managers.sort.sort();
2076
+ else state.managers.render.update(true, true);
2059
2077
  }
2060
2078
  remove(value) {
2061
2079
  if (typeof value === "string") {
@@ -2093,6 +2111,123 @@ const comparators = {
2093
2111
  "starts-with": (row, filter) => startsWith(getString(row), getString(filter), true)
2094
2112
  };
2095
2113
  const equalizer = equal.initialize({ ignoreCase: true });
2114
+ var GroupManager = class {
2115
+ collapsed = /* @__PURE__ */ new Set();
2116
+ enabled = false;
2117
+ field;
2118
+ items = [];
2119
+ order = {};
2120
+ constructor(state) {
2121
+ this.state = state;
2122
+ if (isNullableOrWhitespace(state.options.grouping)) return;
2123
+ this.enabled = true;
2124
+ this.field = state.options.grouping;
2125
+ }
2126
+ add(group) {
2127
+ this.set([...this.items, group]);
2128
+ }
2129
+ get(value) {
2130
+ return this.items.find((item) => item.value === value);
2131
+ }
2132
+ handle(button) {
2133
+ const key = button.dataset.key;
2134
+ const group = this.get(key);
2135
+ if (group == null) return;
2136
+ const { collapsed, items, state } = this;
2137
+ group.expanded = !group.expanded;
2138
+ const index = items.indexOf(group);
2139
+ let first = state.managers.data.values.keys.original.indexOf(items[index]) + 1;
2140
+ const last = items[index + 1] == null ? state.managers.data.keys.length - 1 : state.managers.data.values.keys.original.indexOf(items[index + 1]) - 1;
2141
+ for (; first <= last; first += 1) {
2142
+ const key = state.managers.data.values.keys.original[first];
2143
+ if (group.expanded) collapsed.delete(key);
2144
+ else collapsed.add(key);
2145
+ }
2146
+ state.managers.render.update(true, true);
2147
+ }
2148
+ remove(group) {
2149
+ this.set(this.items.filter((item) => item !== group));
2150
+ }
2151
+ set(items) {
2152
+ this.items = sort(items, (item) => item.label);
2153
+ this.order = toRecord(items, "value", (_, index) => index);
2154
+ }
2155
+ };
2156
+ function getKey(value) {
2157
+ if (typeof value === "number") return value;
2158
+ if (typeof value !== "string") return;
2159
+ return integerExpression.test(value) ? Number.parseInt(value, 10) : value;
2160
+ }
2161
+ const integerExpression = /^\d+$/;
2162
+ var NavigationManager = class {
2163
+ active;
2164
+ constructor(state) {
2165
+ this.state = state;
2166
+ }
2167
+ destroy() {
2168
+ this.state = void 0;
2169
+ }
2170
+ handle(event) {
2171
+ if (!allKeys.has(event.key)) return;
2172
+ event.preventDefault();
2173
+ const { components, id, managers } = this.state;
2174
+ const activeDescendant = components.body.elements.group.getAttribute("aria-activedescendant");
2175
+ const { keys } = managers.data;
2176
+ const { length } = keys;
2177
+ let next;
2178
+ if (isNullableOrWhitespace(activeDescendant)) next = getDefaultIndex(event.key, length);
2179
+ else next = getIndex(event, activeDescendant, id, keys);
2180
+ if (next != null) this.setActive(keys.at(next));
2181
+ }
2182
+ setActive(key, scroll) {
2183
+ const { components, managers, options } = this.state;
2184
+ this.active = key;
2185
+ const active = components.body.elements.group.querySelectorAll("[data-active=\"true\"]");
2186
+ for (const item of active) item.setAttribute("data-active", "false");
2187
+ const row = managers.row.get(key);
2188
+ if (row != null) {
2189
+ row.element?.setAttribute("data-active", "true");
2190
+ if (scroll ?? true) if (row.element == null) components.body.elements.group.scrollTo({
2191
+ top: managers.data.getIndex(key) * options.rowHeight,
2192
+ behavior: "smooth"
2193
+ });
2194
+ else row.element.scrollIntoView({ block: "nearest" });
2195
+ }
2196
+ components.body.elements.group.setAttribute("aria-activedescendant", row == null ? "" : `tabela_${this.state.id}_row_${key}`);
2197
+ }
2198
+ };
2199
+ function getDefaultIndex(key, max) {
2200
+ switch (true) {
2201
+ case negativeDefaultKeys.has(key): return -1;
2202
+ case key === "PageDown": return Math.min(9, max - 1);
2203
+ case key === "PageUp": return max < 10 ? 0 : max - 10;
2204
+ default: return 0;
2205
+ }
2206
+ }
2207
+ function getIndex(event, active, id, keys) {
2208
+ const key = getKey(active.replace(`tabela_${id}_row_`, ""));
2209
+ if (key == null) return;
2210
+ if (absoluteKeys.has(event.key)) return event.key === "Home" ? 0 : keys.length - 1;
2211
+ return clamp(keys.indexOf(key) + getOffset(event.key), 0, keys.length - 1, true);
2212
+ }
2213
+ function getOffset(key) {
2214
+ switch (key) {
2215
+ case "ArrowDown": return 1;
2216
+ case "ArrowUp": return -1;
2217
+ case "PageDown": return 10;
2218
+ case "PageUp": return -10;
2219
+ default: return 0;
2220
+ }
2221
+ }
2222
+ const absoluteKeys = new Set(["End", "Home"]);
2223
+ const arrowKeys = new Set(["ArrowDown", "ArrowUp"]);
2224
+ const negativeDefaultKeys = new Set(["ArrowUp", "End"]);
2225
+ const pageKeys = new Set(["PageDown", "PageUp"]);
2226
+ const allKeys = new Set([
2227
+ ...absoluteKeys,
2228
+ ...arrowKeys,
2229
+ ...pageKeys
2230
+ ]);
2096
2231
  function removeRow(pool, row) {
2097
2232
  if (row.element != null) {
2098
2233
  row.element.innerHTML = "";
@@ -2102,27 +2237,30 @@ function removeRow(pool, row) {
2102
2237
  }
2103
2238
  row.cells = {};
2104
2239
  }
2105
- function renderRow(managers, row) {
2106
- const element = row.element ?? managers.render.pool.rows.shift() ?? createRow();
2240
+ function renderRow(state, row) {
2241
+ const element = row.element ?? state.managers.render.pool.rows.shift() ?? createRow();
2107
2242
  row.element = element;
2108
2243
  element.innerHTML = "";
2109
- const selected = managers.selection.items.has(row.key);
2244
+ const selected = state.managers.selection.items.has(row.key);
2245
+ const key = String(row.key);
2110
2246
  setAttributes(element, {
2111
2247
  "aria-selected": String(selected),
2248
+ "data-active": String(state.managers.navigation.active === row.key),
2112
2249
  "data-event": "row",
2113
- "data-key": String(row.key)
2250
+ "data-key": key,
2251
+ id: `tabela_${state.id}_row_${key}`
2114
2252
  });
2115
2253
  element.classList.add("tabela__row--body");
2116
2254
  if (selected) element.classList.add("tabela__row--selected");
2117
2255
  else element.classList.remove("tabela__row--selected");
2118
- const columns = managers.column.items;
2256
+ const columns = state.managers.column.items;
2119
2257
  const { length } = columns;
2120
- const data = managers.data.values.objects.mapped.get(row.key);
2258
+ const data = state.managers.data.values.objects.mapped.get(row.key);
2121
2259
  if (data == null) return;
2122
2260
  for (let index = 0; index < length; index += 1) {
2123
2261
  const { options } = columns[index];
2124
- managers.render.pool.cells[options.field] ??= [];
2125
- const cell = managers.render.pool.cells[columns[index].options.field].shift() ?? createCell(options.width);
2262
+ state.managers.render.pool.cells[options.field] ??= [];
2263
+ const cell = state.managers.render.pool.cells[columns[index].options.field].shift() ?? createCell(options.width);
2126
2264
  cell.textContent = String(data[options.field]);
2127
2265
  row.cells[options.field] = cell;
2128
2266
  element.append(cell);
@@ -2135,18 +2273,149 @@ var RowComponent = class {
2135
2273
  this.key = key;
2136
2274
  }
2137
2275
  };
2276
+ function getRange(state, down) {
2277
+ const { components, managers, options } = state;
2278
+ const { clientHeight, scrollTop } = components.body.elements.group;
2279
+ const { keys } = managers.data;
2280
+ const first = Math.floor(scrollTop / options.rowHeight);
2281
+ const last = Math.min(keys.length - managers.group.collapsed.size - 1, Math.ceil((scrollTop + clientHeight) / options.rowHeight) - 1);
2282
+ const before = Math.ceil(clientHeight / options.rowHeight) * (down ? 1 : 2);
2283
+ const after = Math.ceil(clientHeight / options.rowHeight) * (down ? 2 : 1);
2284
+ const start = Math.max(0, first - before);
2285
+ return {
2286
+ end: Math.min(keys.length - managers.group.collapsed.size - 1, last + after),
2287
+ start
2288
+ };
2289
+ }
2290
+ function onScroll() {
2291
+ const { state } = this;
2292
+ if (!state.active) {
2293
+ requestAnimationFrame(() => {
2294
+ const top = state.components.body.elements.group.scrollTop;
2295
+ this.update(top > state.top);
2296
+ state.active = false;
2297
+ state.top = top;
2298
+ });
2299
+ state.active = true;
2300
+ }
2301
+ }
2302
+ var RenderManager = class {
2303
+ fragment;
2304
+ listener;
2305
+ pool = {
2306
+ cells: {},
2307
+ rows: []
2308
+ };
2309
+ state;
2310
+ visible = /* @__PURE__ */ new Map();
2311
+ constructor(state) {
2312
+ this.listener = on(state.components.body.elements.group, "scroll", onScroll.bind(this));
2313
+ this.state = {
2314
+ ...state,
2315
+ active: false,
2316
+ top: 0
2317
+ };
2318
+ }
2319
+ destroy() {
2320
+ const { listener, pool, visible } = this;
2321
+ listener();
2322
+ visible.clear();
2323
+ pool.cells = {};
2324
+ pool.rows = [];
2325
+ this.fragment = void 0;
2326
+ this.listener = void 0;
2327
+ this.pool = void 0;
2328
+ this.state = void 0;
2329
+ this.visible = void 0;
2330
+ }
2331
+ removeCells(fields) {
2332
+ const { pool, state, visible } = this;
2333
+ const { length } = fields;
2334
+ for (let index = 0; index < length; index += 1) delete pool.cells[fields[index]];
2335
+ for (const [, key] of visible) {
2336
+ if (key instanceof GroupComponent) continue;
2337
+ const row = state.managers.row.get(key);
2338
+ if (row == null || row.element == null) continue;
2339
+ for (let index = 0; index < length; index += 1) {
2340
+ row.cells[fields[index]].innerHTML = "";
2341
+ row.cells[fields[index]].remove();
2342
+ delete row.cells[fields[index]];
2343
+ }
2344
+ }
2345
+ }
2346
+ getFragment() {
2347
+ this.fragment ??= document.createDocumentFragment();
2348
+ this.fragment.replaceChildren();
2349
+ return this.fragment;
2350
+ }
2351
+ update(down, rerender) {
2352
+ const { state, pool, visible } = this;
2353
+ const { components, managers, options } = state;
2354
+ components.body.elements.faker.style.height = `${(managers.data.size - managers.group.collapsed.size) * options.rowHeight}px`;
2355
+ const indices = /* @__PURE__ */ new Set();
2356
+ const range = getRange(state, down);
2357
+ for (let index = range.start; index <= range.end; index += 1) indices.add(index);
2358
+ let remove = rerender ?? false;
2359
+ for (const [index, key] of visible) {
2360
+ if (key instanceof GroupComponent) {
2361
+ if (remove || !indices.has(index)) {
2362
+ visible.delete(index);
2363
+ key.element?.remove();
2364
+ }
2365
+ continue;
2366
+ }
2367
+ const row = managers.row.get(key);
2368
+ if (remove || row == null || !indices.has(index) || managers.group.collapsed.has(key)) {
2369
+ visible.delete(index);
2370
+ if (row != null) removeRow(pool, row);
2371
+ }
2372
+ }
2373
+ const fragment = this.getFragment();
2374
+ const { keys } = managers.data;
2375
+ let count = 0;
2376
+ let offset = 0;
2377
+ for (let index = range.start; index <= range.end + offset; index += 1) {
2378
+ if (visible.has(index)) continue;
2379
+ const key = keys[index];
2380
+ if (key instanceof GroupComponent) {
2381
+ count += 1;
2382
+ renderGroup(state, key);
2383
+ visible.set(index, key);
2384
+ if (key.element != null) {
2385
+ key.element.style.transform = `translateY(${(index - offset) * options.rowHeight}px)`;
2386
+ fragment.append(key.element);
2387
+ }
2388
+ continue;
2389
+ }
2390
+ const row = managers.row.get(key);
2391
+ if (row == null) continue;
2392
+ if (managers.group.collapsed.has(key)) {
2393
+ offset += 1;
2394
+ continue;
2395
+ }
2396
+ count += 1;
2397
+ renderRow(state, row);
2398
+ visible.set(index, key);
2399
+ if (row.element != null) {
2400
+ row.element.style.transform = `translateY(${(index - offset) * options.rowHeight}px)`;
2401
+ fragment.append(row.element);
2402
+ }
2403
+ }
2404
+ if (count > 0) components.body.elements.group[down ? "append" : "prepend"](fragment);
2405
+ }
2406
+ };
2138
2407
  var RowManager = class {
2139
2408
  components = /* @__PURE__ */ new Map();
2140
- height;
2141
- constructor(managers, rowHeight) {
2142
- this.managers = managers;
2143
- this.height = rowHeight;
2409
+ constructor(state) {
2410
+ this.state = state;
2144
2411
  }
2145
2412
  destroy() {
2146
2413
  const components = [...this.components.values()];
2147
2414
  const { length } = components;
2148
- for (let index = 0; index < length; index += 1) removeRow(this.managers.render.pool, components[index]);
2415
+ for (let index = 0; index < length; index += 1) removeRow(this.state.managers.render.pool, components[index]);
2149
2416
  this.components.clear();
2417
+ this.components = void 0;
2418
+ this.state = void 0;
2150
2419
  }
2151
2420
  get(key) {
2152
2421
  let row = this.components.get(key);
@@ -2162,38 +2431,44 @@ var RowManager = class {
2162
2431
  remove(key) {
2163
2432
  const row = this.components.get(key);
2164
2433
  if (row != null) {
2165
- removeRow(this.managers.render.pool, row);
2434
+ removeRow(this.state.managers.render.pool, row);
2166
2435
  this.components.delete(key);
2167
2436
  }
2168
2437
  }
2169
2438
  update(key) {
2170
2439
  const row = this.components.get(key);
2171
- if (row != null) renderRow(this.managers, row);
2440
+ if (row != null) renderRow(this.state, row);
2172
2441
  }
2173
2442
  };
2174
- function getKey(value) {
2175
- if (typeof value === "number") return value;
2176
- if (typeof value !== "string") return;
2177
- return integerExpression.test(value) ? Number.parseInt(value, 10) : value;
2178
- }
2179
- const integerExpression = /^\d+$/;
2180
2443
  const dragStyling = toggleStyles(document.body, {
2181
2444
  userSelect: "none",
2182
2445
  webkitUserSelect: "none"
2183
2446
  });
2184
2447
  var SelectionManager = class {
2185
2448
  handlers = Object.freeze({
2449
+ add: (keys) => this.add(keys),
2186
2450
  clear: () => this.clear(),
2187
- deselect: (keys) => this.deselect(keys),
2188
- select: (keys) => this.select(keys),
2451
+ remove: (keys) => this.remove(keys),
2452
+ set: (keys) => this.set(keys),
2189
2453
  toggle: () => this.toggle()
2190
2454
  });
2191
2455
  items = /* @__PURE__ */ new Set();
2192
2456
  last;
2193
- constructor(element, managers) {
2194
- this.element = element;
2195
- this.managers = managers;
2196
- mapped.set(element, this);
2457
+ constructor(state) {
2458
+ this.state = state;
2459
+ mapped.set(state.element, this);
2460
+ }
2461
+ add(keys) {
2462
+ const { length } = keys;
2463
+ let update = false;
2464
+ for (let index = 0; index < length; index += 1) {
2465
+ const key = keys[index];
2466
+ if (!this.items.has(key)) {
2467
+ this.items.add(key);
2468
+ update = true;
2469
+ }
2470
+ }
2471
+ if (update) this.update([]);
2197
2472
  }
2198
2473
  clear() {
2199
2474
  if (this.items.size === 0) return;
@@ -2201,70 +2476,60 @@ var SelectionManager = class {
2201
2476
  this.items.clear();
2202
2477
  this.update(removed);
2203
2478
  }
2204
- deselect(keys) {
2205
- const { length } = keys;
2206
- const removed = [];
2207
- for (let index = 0; index < length; index += 1) {
2208
- const key = keys[index];
2209
- if (this.items.delete(key)) removed.push(key);
2210
- }
2211
- if (removed.length > 0) this.update(removed);
2212
- }
2213
2479
  destroy() {
2214
- mapped.delete(this.element);
2480
+ mapped.delete(this.state.element);
2215
2481
  this.handlers = void 0;
2216
- this.element = void 0;
2217
2482
  this.items = void 0;
2483
+ this.last = void 0;
2484
+ this.state = void 0;
2218
2485
  }
2219
2486
  handle(event, target) {
2220
2487
  const key = getKey(target.getAttribute("data-key"));
2221
2488
  if (key == null) return;
2222
2489
  const { items } = this;
2223
2490
  if (event.shiftKey) {
2224
- if (this.last == null) {
2225
- this.last = key;
2226
- return;
2227
- }
2228
- this.range(this.last, key);
2229
- this.last = key;
2491
+ if (this.last == null) this.state.managers.navigation.setActive(key, false);
2492
+ else this.range(this.last, key);
2230
2493
  return;
2231
2494
  }
2232
2495
  this.last = key;
2496
+ this.state.managers.navigation.setActive(key, false);
2233
2497
  if (event.ctrlKey || event.metaKey) {
2234
- if (items.has(key)) this.deselect([key]);
2235
- else this.select([key]);
2498
+ if (items.has(key)) this.remove([key]);
2499
+ else this.add([key]);
2236
2500
  return;
2237
2501
  }
2238
- if (items.has(key)) if (items.size === 1) this.clear();
2239
- else this.set([key]);
2240
- else this.set([key]);
2502
+ this.set([key]);
2241
2503
  }
2242
2504
  range(from, to) {
2505
+ const { state } = this;
2243
2506
  const keyed = isKey(from) && isKey(to);
2244
2507
  const fromKey = keyed ? from : getKey(from.getAttribute("data-key"));
2245
2508
  const toKey = keyed ? to : getKey(to.getAttribute("data-key"));
2246
2509
  if (fromKey === toKey) return;
2247
- const keys = this.managers.data.values.keys.active ?? this.managers.data.values.keys.original;
2248
- const fromIndex = keys.indexOf(fromKey);
2249
- const toIndex = keys.indexOf(toKey);
2510
+ const { keys } = state.managers.data;
2511
+ const fromIndex = state.managers.data.getIndex(fromKey);
2512
+ const toIndex = state.managers.data.getIndex(toKey);
2250
2513
  if (fromIndex === -1 || toIndex === -1) return;
2251
2514
  const [start, end] = fromIndex < toIndex ? [fromIndex, toIndex] : [toIndex, fromIndex];
2252
2515
  const selected = [];
2253
- for (let index = start; index <= end; index += 1) selected.push(keys[index]);
2254
- if (keyed) this.select(selected);
2516
+ for (let index = start; index <= end; index += 1) {
2517
+ const key = keys[index];
2518
+ if (!(key instanceof GroupComponent)) selected.push(key);
2519
+ }
2520
+ if (keyed) this.add(selected);
2255
2521
  else this.set(selected);
2522
+ this.last = toKey;
2523
+ this.state.managers.navigation.setActive(toKey, false);
2256
2524
  }
2257
- select(keys) {
2525
+ remove(keys) {
2258
2526
  const { length } = keys;
2259
- let update = false;
2527
+ const removed = [];
2260
2528
  for (let index = 0; index < length; index += 1) {
2261
2529
  const key = keys[index];
2262
- if (!this.items.has(key)) {
2263
- this.items.add(key);
2264
- update = true;
2265
- }
2530
+ if (this.items.delete(key)) removed.push(key);
2266
2531
  }
2267
- if (update) this.update([]);
2532
+ if (removed.length > 0) this.update(removed);
2268
2533
  }
2269
2534
  set(keys) {
2270
2535
  const { items } = this;
@@ -2275,10 +2540,10 @@ var SelectionManager = class {
2275
2540
  this.update(removed);
2276
2541
  }
2277
2542
  toggle() {
2278
- const { items, managers } = this;
2279
- const all = managers.data.values.keys.active ?? managers.data.values.keys.original;
2280
- if (items.size === all.length) this.clear();
2281
- else this.select(all);
2543
+ const { items, state } = this;
2544
+ const { keys } = state.managers.data;
2545
+ if (items.size === keys.length - state.managers.group.items.length) this.clear();
2546
+ else this.set(keys.filter((key) => !(key instanceof GroupComponent)));
2282
2547
  }
2283
2548
  update(removed) {
2284
2549
  const items = [...removed.map((key) => ({
@@ -2291,7 +2556,7 @@ var SelectionManager = class {
2291
2556
  const { length } = items;
2292
2557
  for (let index = 0; index < length; index += 1) {
2293
2558
  const { key, removed } = items[index];
2294
- const row = this.managers.row.get(key);
2559
+ const row = this.state.managers.row.get(key);
2295
2560
  if (row == null || row.element == null) continue;
2296
2561
  setAttribute(row.element, "aria-selected", String(!removed));
2297
2562
  if (removed) row.element.classList.remove("tabela__row--selected");
@@ -2364,199 +2629,6 @@ on(document, "keyup", onShiftUp);
2364
2629
  on(document, "mousedown", onMouseDown);
2365
2630
  on(document, "mousemove", onMouseMove);
2366
2631
  on(document, "mouseup", onMouseUp);
2367
- var SortManager = class {
2368
- handlers = Object.freeze({
2369
- add: (field, direction) => this.add(field, direction),
2370
- flip: (field) => this.flip(field),
2371
- clear: () => this.clear(),
2372
- remove: (field) => this.remove(field),
2373
- set: (items) => this.set(items)
2374
- });
2375
- items = [];
2376
- constructor(managers) {
2377
- this.managers = managers;
2378
- }
2379
- add(field, direction) {
2380
- if (this.items.findIndex((item) => item.key === field) > -1) return;
2381
- this.items.push({
2382
- key: field,
2383
- direction: direction ?? "ascending"
2384
- });
2385
- this.sort();
2386
- }
2387
- addOrSet(event, field) {
2388
- if (event.ctrlKey || event.metaKey) this.add(field);
2389
- else this.set([{
2390
- field,
2391
- direction: "ascending"
2392
- }]);
2393
- }
2394
- clear() {
2395
- if (this.items.length > 0) {
2396
- this.items.length = 0;
2397
- this.sort();
2398
- }
2399
- }
2400
- destroy() {
2401
- this.handlers = void 0;
2402
- this.items.length = 0;
2403
- }
2404
- flip(field) {
2405
- const item = this.items.find((item) => item.key === field);
2406
- if (item == null) return;
2407
- item.direction = item.direction === "ascending" ? "descending" : "ascending";
2408
- this.sort();
2409
- }
2410
- remove(field) {
2411
- const index = this.items.findIndex((item) => item.key === field);
2412
- if (index > -1) {
2413
- this.items.splice(index, 1);
2414
- this.sort();
2415
- }
2416
- }
2417
- removeOrClear(event, field) {
2418
- if (event.ctrlKey || event.metaKey) this.remove(field);
2419
- else this.clear();
2420
- }
2421
- set(items) {
2422
- this.items.splice(0, this.items.length, ...items.map((item) => ({
2423
- key: item.field,
2424
- direction: item.direction
2425
- })));
2426
- this.sort();
2427
- }
2428
- sort() {
2429
- const { items, managers } = this;
2430
- const { length } = managers.column.items;
2431
- for (let index = 0; index < length; index += 1) {
2432
- const column = managers.column.items[index];
2433
- const sorterIndex = items.findIndex((item) => item.key === column.options.field);
2434
- const sorterItem = items[sorterIndex];
2435
- setAttributes(column.elements.wrapper, {
2436
- "aria-sort": sorterItem == null ? "none" : items.length > 1 ? "other" : sorterItem.direction,
2437
- "data-sort-direction": sorterItem == null ? void 0 : sorterItem.direction
2438
- });
2439
- setAttribute(column.elements.sorter, "data-sort-position", sorterIndex > -1 && items.length > 1 ? sorterIndex + 1 : void 0);
2440
- }
2441
- managers.data.values.keys.active = items.length === 0 ? void 0 : sort(managers.data.values.keys.active?.map((key) => managers.data.values.objects.mapped.get(key)) ?? managers.data.values.objects.array, items).map((row) => row[managers.data.field]);
2442
- managers.render.update(true, true);
2443
- }
2444
- toggle(event, field, direction) {
2445
- switch (direction) {
2446
- case "ascending":
2447
- this.flip(field);
2448
- return;
2449
- case "descending":
2450
- this.removeOrClear(event, field);
2451
- return;
2452
- default:
2453
- this.addOrSet(event, field);
2454
- return;
2455
- }
2456
- }
2457
- };
2458
- function getRange(down) {
2459
- const { components, managers } = this;
2460
- const { clientHeight, scrollTop } = components.body.elements.group;
2461
- const first = Math.floor(scrollTop / managers.row.height);
2462
- const last = Math.min((managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length) - 1, Math.ceil((scrollTop + clientHeight) / managers.row.height) - 1);
2463
- const before = Math.ceil(clientHeight / managers.row.height) * (down ? 1 : 2);
2464
- const after = Math.ceil(clientHeight / managers.row.height) * (down ? 2 : 1);
2465
- const start = Math.max(0, first - before);
2466
- return {
2467
- end: Math.min((managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length) - 1, last + after),
2468
- start
2469
- };
2470
- }
2471
- function onScroll() {
2472
- if (!this.state.active) {
2473
- requestAnimationFrame(() => {
2474
- const top = this.components.body.elements.group.scrollTop;
2475
- this.update(top > this.state.top);
2476
- this.state.active = false;
2477
- this.state.top = top;
2478
- });
2479
- this.state.active = true;
2480
- }
2481
- }
2482
- var RenderManager = class {
2483
- fragment;
2484
- listener;
2485
- pool = {
2486
- cells: {},
2487
- rows: []
2488
- };
2489
- state = {
2490
- active: false,
2491
- top: 0
2492
- };
2493
- visible = /* @__PURE__ */ new Map();
2494
- constructor(managers, components) {
2495
- this.managers = managers;
2496
- this.components = components;
2497
- this.listener = on(components.body.elements.group, "scroll", onScroll.bind(this));
2498
- }
2499
- destroy() {
2500
- const { listener, pool, visible } = this;
2501
- listener();
2502
- visible.clear();
2503
- pool.cells = {};
2504
- pool.rows = [];
2505
- this.listener = void 0;
2506
- this.visible = void 0;
2507
- }
2508
- removeCells(fields) {
2509
- const { managers, pool, visible } = this;
2510
- const { length } = fields;
2511
- for (let index = 0; index < length; index += 1) delete pool.cells[fields[index]];
2512
- for (const [, key] of visible) {
2513
- const row = managers.row.get(key);
2514
- if (row == null || row.element == null) continue;
2515
- for (let index = 0; index < length; index += 1) {
2516
- row.cells[fields[index]].innerHTML = "";
2517
- row.cells[fields[index]].remove();
2518
- delete row.cells[fields[index]];
2519
- }
2520
- }
2521
- }
2522
- getFragment() {
2523
- this.fragment ??= document.createDocumentFragment();
2524
- this.fragment.replaceChildren();
2525
- return this.fragment;
2526
- }
2527
- update(down, rerender) {
2528
- const { components, managers, pool, visible } = this;
2529
- components.body.elements.faker.style.height = `${managers.data.size * managers.row.height}px`;
2530
- const indices = /* @__PURE__ */ new Set();
2531
- const range = getRange.call(this, down);
2532
- for (let index = range.start; index <= range.end; index += 1) indices.add(index);
2533
- let remove = rerender ?? false;
2534
- for (const [index, key] of visible) {
2535
- const row = managers.row.get(key);
2536
- if (remove || row == null || !indices.has(index)) {
2537
- visible.delete(index);
2538
- if (row != null) removeRow(pool, row);
2539
- }
2540
- }
2541
- const fragment = this.getFragment();
2542
- const keys = managers.data.values.keys.active ?? managers.data.values.keys.original;
2543
- let count = 0;
2544
- for (let index = range.start; index <= range.end; index += 1) {
2545
- if (visible.has(index)) continue;
2546
- const key = keys[index];
2547
- const row = managers.row.get(key);
2548
- if (row == null) continue;
2549
- count += 1;
2550
- renderRow(managers, row);
2551
- visible.set(index, key);
2552
- if (row.element != null) {
2553
- row.element.style.transform = `translateY(${index * managers.row.height}px)`;
2554
- fragment.append(row.element);
2555
- }
2556
- }
2557
- if (count > 0) components.body.elements.group[down ? "append" : "prepend"](fragment);
2558
- }
2559
- };
2560
2632
  var Tabela = class {
2561
2633
  #components = {
2562
2634
  header: void 0,
@@ -2564,12 +2636,15 @@ var Tabela = class {
2564
2636
  footer: void 0
2565
2637
  };
2566
2638
  #element;
2639
+ #id = getId();
2567
2640
  #key;
2568
2641
  #managers = {
2569
2642
  column: void 0,
2570
2643
  data: void 0,
2571
2644
  event: void 0,
2572
2645
  filter: void 0,
2646
+ group: void 0,
2647
+ navigation: void 0,
2573
2648
  render: void 0,
2574
2649
  row: void 0,
2575
2650
  selection: void 0,
@@ -2592,14 +2667,24 @@ var Tabela = class {
2592
2667
  this.#components.header = new HeaderComponent();
2593
2668
  this.#components.body = new BodyComponent();
2594
2669
  this.#components.footer = new FooterComponent();
2595
- this.#managers.column = new ColumnManager(this.#managers, this.#components, options.columns);
2596
- this.#managers.data = new DataManager(this.#managers, this.#components, options.key);
2597
- this.#managers.event = new EventManager(this.#element, this.#managers);
2598
- this.#managers.filter = new FilterManager(this.#managers);
2599
- this.#managers.render = new RenderManager(this.#managers, this.#components);
2600
- this.#managers.row = new RowManager(this.#managers, options.rowHeight);
2601
- this.#managers.selection = new SelectionManager(this.#element, this.#managers);
2602
- this.#managers.sort = new SortManager(this.#managers);
2670
+ const state = {
2671
+ element,
2672
+ options,
2673
+ components: this.#components,
2674
+ id: this.#id,
2675
+ key: this.#key,
2676
+ managers: this.#managers
2677
+ };
2678
+ this.#managers.column = new ColumnManager(state);
2679
+ this.#managers.data = new DataManager(state);
2680
+ this.#managers.event = new EventManager(state);
2681
+ this.#managers.filter = new FilterManager(state);
2682
+ this.#managers.group = new GroupManager(state);
2683
+ this.#managers.navigation = new NavigationManager(state);
2684
+ this.#managers.render = new RenderManager(state);
2685
+ this.#managers.row = new RowManager(state);
2686
+ this.#managers.selection = new SelectionManager(state);
2687
+ this.#managers.sort = new SortManager(state);
2603
2688
  element.append(this.#components.header.elements.group, this.#components.body.elements.group, this.#components.footer.elements.group);
2604
2689
  this.#managers.data.set(options.data);
2605
2690
  this.data = this.#managers.data.handlers;
@@ -2620,6 +2705,7 @@ var Tabela = class {
2620
2705
  managers.filter.destroy();
2621
2706
  managers.render.destroy();
2622
2707
  managers.row.destroy();
2708
+ managers.selection.destroy();
2623
2709
  managers.sort.destroy();
2624
2710
  element.innerHTML = "";
2625
2711
  element.role = "";
@@ -2629,6 +2715,11 @@ var Tabela = class {
2629
2715
  this.#element = void 0;
2630
2716
  }
2631
2717
  };
2718
+ function getId() {
2719
+ id += 1;
2720
+ return id;
2721
+ }
2722
+ let id = 0;
2632
2723
  function tabela(element, options) {
2633
2724
  return new Tabela(element, options);
2634
2725
  }