@oscarpalmer/tabela 0.11.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 (64) hide show
  1. package/dist/components/column.component.js +4 -4
  2. package/dist/components/group.component.js +28 -0
  3. package/dist/helpers/dom.helpers.js +1 -1
  4. package/dist/managers/data.manager.js +76 -15
  5. package/dist/managers/event.manager.js +3 -0
  6. package/dist/managers/filter.manager.js +5 -0
  7. package/dist/managers/group.manager.js +46 -0
  8. package/dist/managers/navigation.manager.js +1 -1
  9. package/dist/managers/render.manager.js +35 -10
  10. package/dist/managers/selection.manager.js +32 -27
  11. package/dist/managers/sort.manager.js +29 -2
  12. package/dist/models/group.model.js +0 -0
  13. package/dist/models/selection.model.js +0 -0
  14. package/dist/tabela.full.js +364 -398
  15. package/dist/tabela.js +4 -1
  16. package/package.json +1 -1
  17. package/src/components/column.component.ts +6 -6
  18. package/src/components/group.component.ts +43 -0
  19. package/src/components/row.component.ts +2 -2
  20. package/src/helpers/dom.helpers.ts +3 -1
  21. package/src/managers/column.manager.ts +4 -4
  22. package/src/managers/data.manager.ts +155 -21
  23. package/src/managers/event.manager.ts +7 -3
  24. package/src/managers/filter.manager.ts +19 -11
  25. package/src/managers/group.manager.ts +79 -0
  26. package/src/managers/navigation.manager.ts +6 -5
  27. package/src/managers/render.manager.ts +55 -17
  28. package/src/managers/row.manager.ts +2 -2
  29. package/src/managers/selection.manager.ts +48 -41
  30. package/src/managers/sort.manager.ts +76 -13
  31. package/src/models/column.model.ts +2 -2
  32. package/src/models/data.model.ts +14 -3
  33. package/src/models/filter.model.ts +11 -3
  34. package/src/models/group.model.ts +4 -0
  35. package/src/models/render.model.ts +2 -2
  36. package/src/models/selection.model.ts +9 -0
  37. package/src/models/sort.model.ts +11 -3
  38. package/src/models/tabela.model.ts +7 -41
  39. package/src/models/tabela.options.ts +3 -2
  40. package/src/tabela.ts +11 -12
  41. package/types/components/column.component.d.ts +3 -3
  42. package/types/components/group.component.d.ts +14 -0
  43. package/types/components/row.component.d.ts +2 -2
  44. package/types/helpers/style.helper.d.ts +1 -1
  45. package/types/managers/column.manager.d.ts +5 -5
  46. package/types/managers/data.manager.d.ts +5 -3
  47. package/types/managers/event.manager.d.ts +3 -3
  48. package/types/managers/filter.manager.d.ts +11 -11
  49. package/types/managers/group.manager.d.ts +17 -0
  50. package/types/managers/navigation.manager.d.ts +3 -3
  51. package/types/managers/render.manager.d.ts +4 -3
  52. package/types/managers/row.manager.d.ts +3 -3
  53. package/types/managers/selection.manager.d.ts +12 -6
  54. package/types/managers/sort.manager.d.ts +10 -8
  55. package/types/models/column.model.d.ts +2 -2
  56. package/types/models/data.model.d.ts +13 -3
  57. package/types/models/filter.model.d.ts +10 -3
  58. package/types/models/group.model.d.ts +4 -0
  59. package/types/models/render.model.d.ts +2 -2
  60. package/types/models/selection.model.d.ts +8 -0
  61. package/types/models/sort.model.d.ts +10 -3
  62. package/types/models/tabela.model.d.ts +7 -37
  63. package/types/models/tabela.options.d.ts +3 -2
  64. package/types/tabela.d.ts +4 -1
@@ -319,9 +319,9 @@ new Set([
319
319
  * @returns `true` if the value is nullable or a whitespace-only string, otherwise `false`
320
320
  */
321
321
  function isNullableOrWhitespace$1(value) {
322
- return value == null || EXPRESSION_WHITESPACE$2.test(getString$1(value));
322
+ return value == null || EXPRESSION_WHITESPACE$1.test(getString$1(value));
323
323
  }
324
- var EXPRESSION_WHITESPACE$2 = /^\s*$/;
324
+ var EXPRESSION_WHITESPACE$1 = /^\s*$/;
325
325
  function setElementValue(element, first, second, third, callback) {
326
326
  if (!isHTMLOrSVGElement(element)) return;
327
327
  if (typeof first === "string") setElementValues(element, first, second, third, callback);
@@ -349,52 +349,9 @@ function updateElementValue(element, key, value, set, remove, isBoolean, json) {
349
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$1, ""));
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$1 = /[\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" }, {}, {});
@@ -637,13 +585,13 @@ var HeaderComponent = class {
637
585
  var ColumnComponent = class {
638
586
  elements;
639
587
  options;
640
- constructor(options) {
641
- 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);
642
590
  this.options = {
643
- ...options,
591
+ ...column,
644
592
  width
645
593
  };
646
- this.elements = createHeading(options.field, options.title, width);
594
+ this.elements = createHeading(this.options.field, this.options.title, width);
647
595
  }
648
596
  destroy() {
649
597
  this.elements.content.remove();
@@ -864,35 +812,8 @@ function compact(array, strict) {
864
812
  }
865
813
  return compacted;
866
814
  }
867
- function insertChunkedValues(type, array, items, start, deleteCount) {
868
- const actualDeleteCount = deleteCount < 0 ? 0 : deleteCount;
869
- const actualStart = Math.min(Math.max(0, start), array.length);
870
- const chunked = chunk(items);
871
- const lastIndex = chunked.length - 1;
872
- let index = Number(chunked.length);
873
- let returned;
874
- while (index > 0) {
875
- index -= 1;
876
- const spliced = array.splice(actualStart, index === lastIndex ? actualDeleteCount : 0, ...chunked[index]);
877
- if (returned == null) returned = spliced;
878
- else returned.push(...spliced);
879
- }
880
- if (type === "insert") return array;
881
- return type === "splice" ? returned : array.length;
882
- }
883
- function insertValues(type, array, items, start, deleteCount) {
884
- const spliceArray = type === "insert" || type === "splice";
885
- if (!Array.isArray(array) || typeof start !== "number" || !Array.isArray(items) || items.length === 0) return spliceArray ? [] : 0;
886
- return insertChunkedValues(type, array, items, start, spliceArray ? deleteCount : 0);
887
- }
888
- /**
889
- * Push items into an array _(at the end)_
890
- * @param array Original array
891
- * @param pushed Pushed items
892
- * @returns New length of the array
893
- */
894
- function push(array, pushed) {
895
- return insertValues("push", array, pushed, array.length, 0);
815
+ function select(array, ...parameters) {
816
+ return findValues("all", array, parameters, parameters.pop()).matched;
896
817
  }
897
818
  function aggregate(type, array, key) {
898
819
  const length = Array.isArray(array) ? array.length : 0;
@@ -1159,6 +1080,172 @@ toMap.arrays = toMapArrays;
1159
1080
  function toMapArrays(array, first, second) {
1160
1081
  return getMapValues(array, first, second, true);
1161
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
+ }
1162
1249
  /**
1163
1250
  * Is the value `undefined`, `null`, or a whitespace-only string?
1164
1251
  * @param value Value to check
@@ -1184,17 +1271,41 @@ var DataManager = class {
1184
1271
  array: []
1185
1272
  }
1186
1273
  };
1274
+ get keys() {
1275
+ return this.values.keys.active ?? this.values.keys.original;
1276
+ }
1187
1277
  get size() {
1188
- return this.values.keys.active?.length ?? this.values.keys.original.length;
1278
+ return this.keys.length;
1189
1279
  }
1190
1280
  constructor(state) {
1191
1281
  this.state = state;
1192
1282
  }
1193
1283
  async add(data, render) {
1194
1284
  const { state, values } = this;
1195
- push(values.objects.array, data);
1196
- values.objects.mapped = toMap(values.objects.array, state.key);
1197
- if (render) this.render();
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();
1198
1309
  }
1199
1310
  clear() {
1200
1311
  if (this.values.objects.array.length > 0) this.set([]);
@@ -1211,11 +1322,10 @@ var DataManager = class {
1211
1322
  }
1212
1323
  get(active) {
1213
1324
  const { values } = this;
1214
- 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));
1215
1326
  }
1216
1327
  getIndex(key) {
1217
- const { values } = this;
1218
- return (values.keys.active ?? values.keys.original).indexOf(key);
1328
+ return this.keys.indexOf(key);
1219
1329
  }
1220
1330
  async remove(items, render) {
1221
1331
  const { state, values } = this;
@@ -1225,24 +1335,59 @@ var DataManager = class {
1225
1335
  for (let keyIndex = 0; keyIndex < length; keyIndex += 1) {
1226
1336
  const key = keys[keyIndex];
1227
1337
  values.objects.mapped.delete(key);
1228
- const arrayIndex = values.objects.array.findIndex((object) => object[state.key] === key);
1229
- 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);
1230
1341
  values.keys.original.splice(values.keys.original.indexOf(key), 1);
1231
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);
1232
1353
  }
1233
1354
  if (render) this.render();
1234
1355
  }
1235
1356
  render() {
1236
1357
  const { state, values } = this;
1237
- values.keys.original = sort(values.objects.array.map((item) => item[state.key]));
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]);
1238
1368
  if (Object.keys(state.managers.filter.items).length > 0) state.managers.filter.filter();
1239
1369
  else if (state.managers.sort.items.length > 0) state.managers.sort.sort();
1240
- else state.managers.render.update(true);
1370
+ else state.managers.render.update(true, true);
1241
1371
  }
1242
1372
  set(data) {
1243
1373
  const { state, values } = this;
1244
- values.objects.mapped = toMap(data, state.key);
1245
- values.objects.array = data;
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;
1246
1391
  this.render();
1247
1392
  }
1248
1393
  async synchronize(data, remove) {
@@ -1260,7 +1405,7 @@ var DataManager = class {
1260
1405
  }
1261
1406
  if (keys.size === 0) return;
1262
1407
  if (remove ?? false) {
1263
- const toRemove = values.keys.original.filter((key) => !keys.has(key));
1408
+ const toRemove = values.keys.original.filter((key) => !(key instanceof GroupComponent) && !keys.has(key));
1264
1409
  if (toRemove.length > 0) await this.remove(toRemove, false);
1265
1410
  }
1266
1411
  await this.update(updated);
@@ -1450,6 +1595,9 @@ function onClick(event) {
1450
1595
  const manager = mapped$1.get(table);
1451
1596
  if (manager == null) return;
1452
1597
  switch (target?.getAttribute("data-event")) {
1598
+ case "group":
1599
+ manager.state.managers.group.handle(target);
1600
+ break;
1453
1601
  case "heading":
1454
1602
  manager.onSort(event, target);
1455
1603
  break;
@@ -1906,6 +2054,10 @@ var FilterManager = class {
1906
2054
  const keysLength = state.managers.data.values.keys.original.length;
1907
2055
  rowLoop: for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
1908
2056
  const key = state.managers.data.values.keys.original[keyIndex];
2057
+ if (key instanceof GroupComponent) {
2058
+ filtered.push(key);
2059
+ continue;
2060
+ }
1909
2061
  const row = state.managers.data.values.objects.mapped.get(key);
1910
2062
  if (row == null) continue;
1911
2063
  filterLoop: for (let filterIndex = 0; filterIndex < filters.length; filterIndex += 1) {
@@ -1959,6 +2111,48 @@ const comparators = {
1959
2111
  "starts-with": (row, filter) => startsWith(getString(row), getString(filter), true)
1960
2112
  };
1961
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
+ };
1962
2156
  function getKey(value) {
1963
2157
  if (typeof value === "number") return value;
1964
2158
  if (typeof value !== "string") return;
@@ -1978,7 +2172,7 @@ var NavigationManager = class {
1978
2172
  event.preventDefault();
1979
2173
  const { components, id, managers } = this.state;
1980
2174
  const activeDescendant = components.body.elements.group.getAttribute("aria-activedescendant");
1981
- const keys = managers.data.values.keys.active ?? managers.data.values.keys.original;
2175
+ const { keys } = managers.data;
1982
2176
  const { length } = keys;
1983
2177
  let next;
1984
2178
  if (isNullableOrWhitespace(activeDescendant)) next = getDefaultIndex(event.key, length);
@@ -2079,16 +2273,17 @@ var RowComponent = class {
2079
2273
  this.key = key;
2080
2274
  }
2081
2275
  };
2082
- function getRange(down) {
2083
- const { components, managers, options } = this.state;
2276
+ function getRange(state, down) {
2277
+ const { components, managers, options } = state;
2084
2278
  const { clientHeight, scrollTop } = components.body.elements.group;
2279
+ const { keys } = managers.data;
2085
2280
  const first = Math.floor(scrollTop / options.rowHeight);
2086
- const last = Math.min((managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length) - 1, Math.ceil((scrollTop + clientHeight) / options.rowHeight) - 1);
2281
+ const last = Math.min(keys.length - managers.group.collapsed.size - 1, Math.ceil((scrollTop + clientHeight) / options.rowHeight) - 1);
2087
2282
  const before = Math.ceil(clientHeight / options.rowHeight) * (down ? 1 : 2);
2088
2283
  const after = Math.ceil(clientHeight / options.rowHeight) * (down ? 2 : 1);
2089
2284
  const start = Math.max(0, first - before);
2090
2285
  return {
2091
- end: Math.min((managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length) - 1, last + after),
2286
+ end: Math.min(keys.length - managers.group.collapsed.size - 1, last + after),
2092
2287
  start
2093
2288
  };
2094
2289
  }
@@ -2138,6 +2333,7 @@ var RenderManager = class {
2138
2333
  const { length } = fields;
2139
2334
  for (let index = 0; index < length; index += 1) delete pool.cells[fields[index]];
2140
2335
  for (const [, key] of visible) {
2336
+ if (key instanceof GroupComponent) continue;
2141
2337
  const row = state.managers.row.get(key);
2142
2338
  if (row == null || row.element == null) continue;
2143
2339
  for (let index = 0; index < length; index += 1) {
@@ -2155,31 +2351,53 @@ var RenderManager = class {
2155
2351
  update(down, rerender) {
2156
2352
  const { state, pool, visible } = this;
2157
2353
  const { components, managers, options } = state;
2158
- components.body.elements.faker.style.height = `${managers.data.size * options.rowHeight}px`;
2354
+ components.body.elements.faker.style.height = `${(managers.data.size - managers.group.collapsed.size) * options.rowHeight}px`;
2159
2355
  const indices = /* @__PURE__ */ new Set();
2160
- const range = getRange.call(this, down);
2356
+ const range = getRange(state, down);
2161
2357
  for (let index = range.start; index <= range.end; index += 1) indices.add(index);
2162
2358
  let remove = rerender ?? false;
2163
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
+ }
2164
2367
  const row = managers.row.get(key);
2165
- if (remove || row == null || !indices.has(index)) {
2368
+ if (remove || row == null || !indices.has(index) || managers.group.collapsed.has(key)) {
2166
2369
  visible.delete(index);
2167
2370
  if (row != null) removeRow(pool, row);
2168
2371
  }
2169
2372
  }
2170
2373
  const fragment = this.getFragment();
2171
- const keys = managers.data.values.keys.active ?? managers.data.values.keys.original;
2374
+ const { keys } = managers.data;
2172
2375
  let count = 0;
2173
- for (let index = range.start; index <= range.end; index += 1) {
2376
+ let offset = 0;
2377
+ for (let index = range.start; index <= range.end + offset; index += 1) {
2174
2378
  if (visible.has(index)) continue;
2175
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
+ }
2176
2390
  const row = managers.row.get(key);
2177
2391
  if (row == null) continue;
2392
+ if (managers.group.collapsed.has(key)) {
2393
+ offset += 1;
2394
+ continue;
2395
+ }
2178
2396
  count += 1;
2179
2397
  renderRow(state, row);
2180
2398
  visible.set(index, key);
2181
2399
  if (row.element != null) {
2182
- row.element.style.transform = `translateY(${index * options.rowHeight}px)`;
2400
+ row.element.style.transform = `translateY(${(index - offset) * options.rowHeight}px)`;
2183
2401
  fragment.append(row.element);
2184
2402
  }
2185
2403
  }
@@ -2222,181 +2440,16 @@ var RowManager = class {
2222
2440
  if (row != null) renderRow(this.state, row);
2223
2441
  }
2224
2442
  };
2225
- function isInert(item) {
2226
- return (item.element.inert ?? false) || EXPRESSION_TRUEISH.test(item.element.getAttribute(ATTRIBUTE_INERT)) || item.element.parentElement != null && isInert({
2227
- element: item.element.parentElement,
2228
- tabIndex: TABINDEX_DEFAULT
2229
- });
2230
- }
2231
- var ATTRIBUTE_INERT = "inert";
2232
- var EXPRESSION_TRUEISH = /^(|true)$/i;
2233
- [
2234
- "[contenteditable]:not([contenteditable=\"false\"])",
2235
- "[tabindex]:not(slot)",
2236
- "a[href]",
2237
- "audio[controls]",
2238
- "button",
2239
- "details",
2240
- "details > summary:first-of-type",
2241
- "input",
2242
- "select",
2243
- "textarea",
2244
- "video[controls]"
2245
- ].map((selector) => `${selector}:not([inert])`).join(",");
2246
- var TABINDEX_DEFAULT = -1;
2247
- function handleElement(element, depth) {
2248
- if (depth === 0) {
2249
- const removable = element.querySelectorAll(REMOVE_SELECTOR);
2250
- for (const item of removable) item.remove();
2251
- }
2252
- sanitizeAttributes(element, [...element.attributes]);
2253
- }
2254
- /**
2255
- * Is the element clobbered?
2256
- *
2257
- * Thanks, DOMPurify _(https://github.com/cure53/DOMPurify)_
2258
- */
2259
- function isClobbered(value) {
2260
- 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");
2261
- }
2262
- function removeNode(node) {
2263
- if (typeof node.remove === "function") node.remove();
2264
- }
2265
- function sanitizeAttributes(element, attributes) {
2266
- const { length } = attributes;
2267
- for (let index = 0; index < length; index += 1) {
2268
- const { name, value } = attributes[index];
2269
- if (_isBadAttribute(name, value, false) || _isEmptyNonBooleanAttribute(name, value, false)) element.removeAttribute(name);
2270
- else if (_isInvalidBooleanAttribute(name, value, false)) setAttribute(element, name, true);
2271
- }
2272
- }
2273
- function sanitizeNodes(nodes, depth) {
2274
- const actual = nodes.filter((node) => node instanceof Node);
2275
- let { length } = nodes;
2276
- for (let index = 0; index < length; index += 1) {
2277
- const node = actual[index];
2278
- let remove = isClobbered(node);
2279
- if (!remove) switch (node.nodeType) {
2280
- case Node.ELEMENT_NODE:
2281
- handleElement(node, depth);
2282
- break;
2283
- case Node.COMMENT_NODE:
2284
- remove = COMMENT_HARMFUL.test(node.data);
2285
- break;
2286
- case Node.DOCUMENT_TYPE_NODE:
2287
- case Node.PROCESSING_INSTRUCTION_NODE:
2288
- remove = true;
2289
- break;
2290
- }
2291
- if (remove) {
2292
- removeNode(node);
2293
- actual.splice(index, 1);
2294
- index -= 1;
2295
- length -= 1;
2296
- continue;
2297
- }
2298
- if (node.hasChildNodes()) sanitizeNodes([...node.childNodes], depth + 1);
2299
- }
2300
- return nodes;
2301
- }
2302
- var COMMENT_HARMFUL = /<[/\w]/g;
2303
- var REMOVE_SELECTOR = "script, toretto-temporary";
2304
- function createHtml(value) {
2305
- const parsed = getParser().parseFromString(getHtml(value), PARSE_TYPE_HTML);
2306
- parsed.body.normalize();
2307
- sanitizeNodes([parsed.body], 0);
2308
- return parsed.body.innerHTML;
2309
- }
2310
- function createTemplate(value, options) {
2311
- const template = document.createElement(TEMPLATE_TAG);
2312
- template.innerHTML = createHtml(value);
2313
- if (typeof value === "string" && options.cache) templates[value] = template;
2314
- return template;
2315
- }
2316
- function getHtml(value) {
2317
- return `${TEMPORARY_ELEMENT}${typeof value === "string" ? value : value.innerHTML}${TEMPORARY_ELEMENT}`;
2318
- }
2319
- function getNodes(value, options) {
2320
- if (typeof value !== "string" && !(value instanceof HTMLTemplateElement)) return [];
2321
- const template = getTemplate(value, options);
2322
- return template == null ? [] : [...template.content.cloneNode(true).childNodes];
2323
- }
2324
- function getOptions(input) {
2325
- const options = isPlainObject$1(input) ? input : {};
2326
- options.cache = typeof options.cache === "boolean" ? options.cache : true;
2327
- return options;
2328
- }
2329
- function getParser() {
2330
- parser ??= new DOMParser();
2331
- return parser;
2332
- }
2333
- function getTemplate(value, options) {
2334
- if (value instanceof HTMLTemplateElement) return createTemplate(value, options);
2335
- if (value.trim().length === 0) return;
2336
- let template = templates[value];
2337
- if (template != null) return template;
2338
- const element = EXPRESSION_ID.test(value) ? document.querySelector(`#${value}`) : null;
2339
- return createTemplate(element instanceof HTMLTemplateElement ? element : value, options);
2340
- }
2341
- var html = ((value, options) => {
2342
- return getNodes(value, getOptions(options));
2343
- });
2344
- html.clear = () => {
2345
- templates = {};
2346
- };
2347
- html.remove = (template) => {
2348
- if (typeof template !== "string" || templates[template] == null) return;
2349
- const keys = Object.keys(templates);
2350
- const { length } = keys;
2351
- const updated = {};
2352
- for (let index = 0; index < length; index += 1) {
2353
- const key = keys[index];
2354
- if (key !== template) updated[key] = templates[key];
2355
- }
2356
- templates = updated;
2357
- };
2358
- var EXPRESSION_ID = /^[a-z][\w-]*$/i;
2359
- var PARSE_TYPE_HTML = "text/html";
2360
- var TEMPLATE_TAG = "template";
2361
- var TEMPORARY_ELEMENT = "<toretto-temporary></toretto-temporary>";
2362
- var parser;
2363
- var templates = {};
2364
- function getSupport() {
2365
- if (window == null || navigator == null) return false;
2366
- if ("matchMedia" in window) {
2367
- const media = matchMedia?.("(pointer: coarse)");
2368
- if (typeof media?.matches === "boolean" && media.matches) return true;
2369
- }
2370
- if ("ontouchstart" in window) return true;
2371
- if (typeof navigator.maxTouchPoints === "number" && navigator.maxTouchPoints > 0) return true;
2372
- if (typeof navigator.msMaxTouchPoints === "number" && navigator.msMaxTouchPoints > 0) return true;
2373
- return false;
2374
- }
2375
- (() => {
2376
- let support = getSupport();
2377
- const instance = Object.create({
2378
- get() {
2379
- return support;
2380
- },
2381
- update() {
2382
- support = getSupport();
2383
- return support;
2384
- }
2385
- });
2386
- Object.defineProperty(instance, "value", { get() {
2387
- return support;
2388
- } });
2389
- return instance;
2390
- })();
2391
2443
  const dragStyling = toggleStyles(document.body, {
2392
2444
  userSelect: "none",
2393
2445
  webkitUserSelect: "none"
2394
2446
  });
2395
2447
  var SelectionManager = class {
2396
2448
  handlers = Object.freeze({
2449
+ add: (keys) => this.add(keys),
2397
2450
  clear: () => this.clear(),
2398
- deselect: (keys) => this.deselect(keys),
2399
- select: (keys) => this.select(keys),
2451
+ remove: (keys) => this.remove(keys),
2452
+ set: (keys) => this.set(keys),
2400
2453
  toggle: () => this.toggle()
2401
2454
  });
2402
2455
  items = /* @__PURE__ */ new Set();
@@ -2405,21 +2458,24 @@ var SelectionManager = class {
2405
2458
  this.state = state;
2406
2459
  mapped.set(state.element, this);
2407
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([]);
2472
+ }
2408
2473
  clear() {
2409
2474
  if (this.items.size === 0) return;
2410
2475
  const removed = [...this.items];
2411
2476
  this.items.clear();
2412
2477
  this.update(removed);
2413
2478
  }
2414
- deselect(keys) {
2415
- const { length } = keys;
2416
- const removed = [];
2417
- for (let index = 0; index < length; index += 1) {
2418
- const key = keys[index];
2419
- if (this.items.delete(key)) removed.push(key);
2420
- }
2421
- if (removed.length > 0) this.update(removed);
2422
- }
2423
2479
  destroy() {
2424
2480
  mapped.delete(this.state.element);
2425
2481
  this.handlers = void 0;
@@ -2439,8 +2495,8 @@ var SelectionManager = class {
2439
2495
  this.last = key;
2440
2496
  this.state.managers.navigation.setActive(key, false);
2441
2497
  if (event.ctrlKey || event.metaKey) {
2442
- if (items.has(key)) this.deselect([key]);
2443
- else this.select([key]);
2498
+ if (items.has(key)) this.remove([key]);
2499
+ else this.add([key]);
2444
2500
  return;
2445
2501
  }
2446
2502
  this.set([key]);
@@ -2451,29 +2507,29 @@ var SelectionManager = class {
2451
2507
  const fromKey = keyed ? from : getKey(from.getAttribute("data-key"));
2452
2508
  const toKey = keyed ? to : getKey(to.getAttribute("data-key"));
2453
2509
  if (fromKey === toKey) return;
2454
- const keys = state.managers.data.values.keys.active ?? state.managers.data.values.keys.original;
2510
+ const { keys } = state.managers.data;
2455
2511
  const fromIndex = state.managers.data.getIndex(fromKey);
2456
2512
  const toIndex = state.managers.data.getIndex(toKey);
2457
2513
  if (fromIndex === -1 || toIndex === -1) return;
2458
2514
  const [start, end] = fromIndex < toIndex ? [fromIndex, toIndex] : [toIndex, fromIndex];
2459
2515
  const selected = [];
2460
- for (let index = start; index <= end; index += 1) selected.push(keys[index]);
2461
- 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);
2462
2521
  else this.set(selected);
2463
2522
  this.last = toKey;
2464
2523
  this.state.managers.navigation.setActive(toKey, false);
2465
2524
  }
2466
- select(keys) {
2525
+ remove(keys) {
2467
2526
  const { length } = keys;
2468
- let update = false;
2527
+ const removed = [];
2469
2528
  for (let index = 0; index < length; index += 1) {
2470
2529
  const key = keys[index];
2471
- if (!this.items.has(key)) {
2472
- this.items.add(key);
2473
- update = true;
2474
- }
2530
+ if (this.items.delete(key)) removed.push(key);
2475
2531
  }
2476
- if (update) this.update([]);
2532
+ if (removed.length > 0) this.update(removed);
2477
2533
  }
2478
2534
  set(keys) {
2479
2535
  const { items } = this;
@@ -2485,9 +2541,9 @@ var SelectionManager = class {
2485
2541
  }
2486
2542
  toggle() {
2487
2543
  const { items, state } = this;
2488
- const all = state.managers.data.values.keys.active ?? state.managers.data.values.keys.original;
2489
- if (items.size === all.length) this.clear();
2490
- else this.select(all);
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)));
2491
2547
  }
2492
2548
  update(removed) {
2493
2549
  const items = [...removed.map((key) => ({
@@ -2573,98 +2629,6 @@ on(document, "keyup", onShiftUp);
2573
2629
  on(document, "mousedown", onMouseDown);
2574
2630
  on(document, "mousemove", onMouseMove);
2575
2631
  on(document, "mouseup", onMouseUp);
2576
- var SortManager = class {
2577
- handlers = Object.freeze({
2578
- add: (field, direction) => this.add(field, direction),
2579
- flip: (field) => this.flip(field),
2580
- clear: () => this.clear(),
2581
- remove: (field) => this.remove(field),
2582
- set: (items) => this.set(items)
2583
- });
2584
- items = [];
2585
- constructor(state) {
2586
- this.state = state;
2587
- }
2588
- add(field, direction) {
2589
- if (this.items.findIndex((item) => item.key === field) > -1) return;
2590
- this.items.push({
2591
- key: field,
2592
- direction: direction ?? "ascending"
2593
- });
2594
- this.sort();
2595
- }
2596
- addOrSet(event, field) {
2597
- if (event.ctrlKey || event.metaKey) this.add(field);
2598
- else this.set([{
2599
- field,
2600
- direction: "ascending"
2601
- }]);
2602
- }
2603
- clear() {
2604
- if (this.items.length > 0) {
2605
- this.items.length = 0;
2606
- this.sort();
2607
- }
2608
- }
2609
- destroy() {
2610
- this.handlers = void 0;
2611
- this.items = void 0;
2612
- this.state = void 0;
2613
- }
2614
- flip(field) {
2615
- const item = this.items.find((item) => item.key === field);
2616
- if (item == null) return;
2617
- item.direction = item.direction === "ascending" ? "descending" : "ascending";
2618
- this.sort();
2619
- }
2620
- remove(field) {
2621
- const index = this.items.findIndex((item) => item.key === field);
2622
- if (index > -1) {
2623
- this.items.splice(index, 1);
2624
- this.sort();
2625
- }
2626
- }
2627
- removeOrClear(event, field) {
2628
- if (event.ctrlKey || event.metaKey) this.remove(field);
2629
- else this.clear();
2630
- }
2631
- set(items) {
2632
- this.items.splice(0, this.items.length, ...items.map((item) => ({
2633
- key: item.field,
2634
- direction: item.direction
2635
- })));
2636
- this.sort();
2637
- }
2638
- sort() {
2639
- const { items, state } = this;
2640
- const { length } = state.managers.column.items;
2641
- for (let index = 0; index < length; index += 1) {
2642
- const column = state.managers.column.items[index];
2643
- const sorterIndex = items.findIndex((item) => item.key === column.options.field);
2644
- const sorterItem = items[sorterIndex];
2645
- setAttributes(column.elements.wrapper, {
2646
- "aria-sort": sorterItem == null ? "none" : items.length > 1 ? "other" : sorterItem.direction,
2647
- "data-sort-direction": sorterItem == null ? void 0 : sorterItem.direction
2648
- });
2649
- setAttribute(column.elements.sorter, "data-sort-position", sorterIndex > -1 && items.length > 1 ? sorterIndex + 1 : void 0);
2650
- }
2651
- state.managers.data.values.keys.active = items.length === 0 ? void 0 : sort(state.managers.data.values.keys.active?.map((key) => state.managers.data.values.objects.mapped.get(key)) ?? state.managers.data.values.objects.array, items).map((row) => row[state.key]);
2652
- state.managers.render.update(true, true);
2653
- }
2654
- toggle(event, field, direction) {
2655
- switch (direction) {
2656
- case "ascending":
2657
- this.flip(field);
2658
- return;
2659
- case "descending":
2660
- this.removeOrClear(event, field);
2661
- return;
2662
- default:
2663
- this.addOrSet(event, field);
2664
- return;
2665
- }
2666
- }
2667
- };
2668
2632
  var Tabela = class {
2669
2633
  #components = {
2670
2634
  header: void 0,
@@ -2679,6 +2643,7 @@ var Tabela = class {
2679
2643
  data: void 0,
2680
2644
  event: void 0,
2681
2645
  filter: void 0,
2646
+ group: void 0,
2682
2647
  navigation: void 0,
2683
2648
  render: void 0,
2684
2649
  row: void 0,
@@ -2714,6 +2679,7 @@ var Tabela = class {
2714
2679
  this.#managers.data = new DataManager(state);
2715
2680
  this.#managers.event = new EventManager(state);
2716
2681
  this.#managers.filter = new FilterManager(state);
2682
+ this.#managers.group = new GroupManager(state);
2717
2683
  this.#managers.navigation = new NavigationManager(state);
2718
2684
  this.#managers.render = new RenderManager(state);
2719
2685
  this.#managers.row = new RowManager(state);