@oscarpalmer/tabela 0.10.0 → 0.11.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 (40) hide show
  1. package/dist/components/body.component.js +1 -0
  2. package/dist/components/row.component.js +11 -8
  3. package/dist/managers/column.manager.js +9 -8
  4. package/dist/managers/data.manager.js +26 -22
  5. package/dist/managers/event.manager.js +39 -23
  6. package/dist/managers/filter.manager.js +11 -10
  7. package/dist/managers/navigation.manager.js +73 -0
  8. package/dist/managers/render.manager.js +30 -25
  9. package/dist/managers/row.manager.js +7 -7
  10. package/dist/managers/selection.manager.js +19 -21
  11. package/dist/managers/sort.manager.js +9 -8
  12. package/dist/tabela.full.js +535 -410
  13. package/dist/tabela.js +27 -9
  14. package/package.json +1 -1
  15. package/src/components/body.component.ts +2 -0
  16. package/src/components/row.component.ts +14 -9
  17. package/src/managers/column.manager.ts +11 -13
  18. package/src/managers/data.manager.ts +31 -27
  19. package/src/managers/event.manager.ts +65 -42
  20. package/src/managers/filter.manager.ts +12 -11
  21. package/src/managers/navigation.manager.ts +145 -0
  22. package/src/managers/render.manager.ts +34 -28
  23. package/src/managers/row.manager.ts +9 -14
  24. package/src/managers/selection.manager.ts +24 -30
  25. package/src/managers/sort.manager.ts +14 -14
  26. package/src/models/render.model.ts +3 -1
  27. package/src/models/tabela.model.ts +12 -0
  28. package/src/tabela.ts +34 -9
  29. package/types/components/row.component.d.ts +2 -2
  30. package/types/managers/column.manager.d.ts +4 -5
  31. package/types/managers/data.manager.d.ts +5 -6
  32. package/types/managers/event.manager.d.ts +3 -6
  33. package/types/managers/filter.manager.d.ts +3 -3
  34. package/types/managers/navigation.manager.d.ts +10 -0
  35. package/types/managers/render.manager.d.ts +4 -6
  36. package/types/managers/row.manager.d.ts +4 -5
  37. package/types/managers/selection.manager.d.ts +3 -4
  38. package/types/managers/sort.manager.d.ts +4 -4
  39. package/types/models/render.model.d.ts +2 -1
  40. package/types/models/tabela.model.d.ts +11 -0
@@ -318,10 +318,10 @@ 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) {
322
- return value == null || EXPRESSION_WHITESPACE$1.test(getString$1(value));
321
+ function isNullableOrWhitespace$1(value) {
322
+ return value == null || EXPRESSION_WHITESPACE$2.test(getString$1(value));
323
323
  }
324
- var EXPRESSION_WHITESPACE$1 = /^\s*$/;
324
+ var EXPRESSION_WHITESPACE$2 = /^\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);
@@ -346,7 +346,7 @@ 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
352
  function badAttributeHandler(name, value) {
@@ -378,7 +378,7 @@ function handleAttribute(callback, decode, first, second) {
378
378
  value = second;
379
379
  }
380
380
  if (decode && value != null) value = decodeAttribute(value);
381
- return callback(name, value?.replace(EXPRESSION_WHITESPACE, ""));
381
+ return callback(name, value?.replace(EXPRESSION_WHITESPACE$1, ""));
382
382
  }
383
383
  function isAttribute(value) {
384
384
  return value instanceof Attr || isPlainObject$1(value) && typeof value.name === "string" && "value" in value;
@@ -415,7 +415,7 @@ var EXPRESSION_SKIP_NAME = /^(aria-[-\w]+|data-[-\w.\u00B7-\uFFFF]+)$/i;
415
415
  var EXPRESSION_SOURCE_NAME = /^src$/i;
416
416
  var EXPRESSION_SOURCE_VALUE = /^data:/i;
417
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;
418
+ var EXPRESSION_WHITESPACE$1 = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g;
419
419
  /**
420
420
  * List of boolean attributes
421
421
  */
@@ -575,6 +575,7 @@ var BodyComponent = class {
575
575
  this.elements.group = group;
576
576
  group.className += " tabela__rowgroup--body";
577
577
  group.tabIndex = 0;
578
+ group.setAttribute("data-event", "body");
578
579
  group.append(this.elements.faker);
579
580
  }
580
581
  destroy() {
@@ -674,18 +675,19 @@ function createHeading(field, title, width) {
674
675
  }
675
676
  var ColumnManager = class {
676
677
  items = [];
677
- constructor(managers, components, columns) {
678
- this.managers = managers;
679
- this.components = components;
680
- this.set(columns);
678
+ constructor(state) {
679
+ this.state = state;
680
+ this.set(state.options.columns);
681
681
  }
682
682
  destroy() {
683
683
  const { length } = this.items;
684
684
  for (let index = 0; index < length; index += 1) this.items[index].destroy();
685
- this.items.length = 0;
685
+ this.items = void 0;
686
+ this.state = void 0;
686
687
  }
687
688
  remove(value) {
688
- const { components, items, managers } = this;
689
+ const { items, state } = this;
690
+ const { components, managers } = state;
689
691
  const fields = (Array.isArray(value) ? value : [value]).filter((item) => typeof item === "string");
690
692
  const { length } = fields;
691
693
  if (length === 0) return;
@@ -701,8 +703,8 @@ var ColumnManager = class {
701
703
  managers.render.removeCells(fields);
702
704
  }
703
705
  set(columns) {
704
- const { components, items } = this;
705
- const { footer, header } = components;
706
+ const { items, state } = this;
707
+ const { footer, header } = state.components;
706
708
  items.splice(0, items.length, ...columns.map((column) => new ColumnComponent(column)));
707
709
  header.update(items);
708
710
  footer.update(items);
@@ -1157,6 +1159,15 @@ toMap.arrays = toMapArrays;
1157
1159
  function toMapArrays(array, first, second) {
1158
1160
  return getMapValues(array, first, second, true);
1159
1161
  }
1162
+ /**
1163
+ * Is the value `undefined`, `null`, or a whitespace-only string?
1164
+ * @param value Value to check
1165
+ * @returns `true` if the value is nullable or a whitespace-only string, otherwise `false`
1166
+ */
1167
+ function isNullableOrWhitespace(value) {
1168
+ return value == null || EXPRESSION_WHITESPACE.test(getString(value));
1169
+ }
1170
+ var EXPRESSION_WHITESPACE = /^\s*$/;
1160
1171
  var DataManager = class {
1161
1172
  handlers = Object.freeze({
1162
1173
  add: (data) => void this.add(data, true),
@@ -1176,15 +1187,13 @@ var DataManager = class {
1176
1187
  get size() {
1177
1188
  return this.values.keys.active?.length ?? this.values.keys.original.length;
1178
1189
  }
1179
- constructor(managers, components, field) {
1180
- this.managers = managers;
1181
- this.components = components;
1182
- this.field = field;
1190
+ constructor(state) {
1191
+ this.state = state;
1183
1192
  }
1184
1193
  async add(data, render) {
1185
- const { field, values } = this;
1194
+ const { state, values } = this;
1186
1195
  push(values.objects.array, data);
1187
- values.objects.mapped = toMap(values.objects.array, field);
1196
+ values.objects.mapped = toMap(values.objects.array, state.key);
1188
1197
  if (render) this.render();
1189
1198
  }
1190
1199
  clear() {
@@ -1197,48 +1206,54 @@ var DataManager = class {
1197
1206
  values.keys.original.length = 0;
1198
1207
  values.objects.array.length = 0;
1199
1208
  this.handlers = void 0;
1209
+ this.state = void 0;
1210
+ this.values = void 0;
1200
1211
  }
1201
1212
  get(active) {
1202
1213
  const { values } = this;
1203
1214
  return active ?? false ? values.keys.active?.map((key) => values.objects.mapped.get(key)) ?? [] : values.objects.array;
1204
1215
  }
1216
+ getIndex(key) {
1217
+ const { values } = this;
1218
+ return (values.keys.active ?? values.keys.original).indexOf(key);
1219
+ }
1205
1220
  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));
1221
+ const { state, values } = this;
1222
+ const keys = items.map((value) => isPlainObject(value) ? value[state.key] : value).filter((key) => values.objects.mapped.has(key));
1208
1223
  const { length } = keys;
1209
1224
  if (length === 0) return;
1210
1225
  for (let keyIndex = 0; keyIndex < length; keyIndex += 1) {
1211
1226
  const key = keys[keyIndex];
1212
1227
  values.objects.mapped.delete(key);
1213
- const arrayIndex = values.objects.array.findIndex((object) => object[field] === key);
1228
+ const arrayIndex = values.objects.array.findIndex((object) => object[state.key] === key);
1214
1229
  if (arrayIndex > -1) values.objects.array.splice(arrayIndex, 1);
1215
1230
  values.keys.original.splice(values.keys.original.indexOf(key), 1);
1216
- managers.row.remove(key);
1231
+ state.managers.row.remove(key);
1217
1232
  }
1218
1233
  if (render) this.render();
1219
1234
  }
1220
1235
  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);
1236
+ const { state, values } = this;
1237
+ values.keys.original = sort(values.objects.array.map((item) => item[state.key]));
1238
+ if (Object.keys(state.managers.filter.items).length > 0) state.managers.filter.filter();
1239
+ else if (state.managers.sort.items.length > 0) state.managers.sort.sort();
1240
+ else state.managers.render.update(true);
1226
1241
  }
1227
1242
  set(data) {
1228
- const { field, values } = this;
1229
- values.objects.mapped = toMap(data, field);
1243
+ const { state, values } = this;
1244
+ values.objects.mapped = toMap(data, state.key);
1230
1245
  values.objects.array = data;
1231
1246
  this.render();
1232
1247
  }
1233
1248
  async synchronize(data, remove) {
1234
- const { field, values } = this;
1249
+ const { state, values } = this;
1235
1250
  const add = [];
1236
1251
  const updated = [];
1237
1252
  const keys = /* @__PURE__ */ new Set([]);
1238
1253
  const { length } = data;
1239
1254
  for (let index = 0; index < length; index += 1) {
1240
1255
  const object = data[index];
1241
- const key = object[field];
1256
+ const key = object[state.key];
1242
1257
  if (values.objects.mapped.has(key)) updated.push(object);
1243
1258
  else add.push(object);
1244
1259
  keys.add(key);
@@ -1253,18 +1268,18 @@ var DataManager = class {
1253
1268
  if (add.length > 0 || (remove ?? false)) this.render();
1254
1269
  }
1255
1270
  async update(data) {
1256
- const { field, managers, values } = this;
1271
+ const { state, values } = this;
1257
1272
  const { length } = data;
1258
1273
  for (let index = 0; index < length; index += 1) {
1259
1274
  const object = data[index];
1260
- const key = object[field];
1275
+ const key = object[state.key];
1261
1276
  const value = values.objects.mapped.get(key);
1262
1277
  if (value != null) {
1263
1278
  values.objects.mapped.set(key, {
1264
1279
  ...value,
1265
1280
  ...object
1266
1281
  });
1267
- managers.row.update(key);
1282
+ state.managers.row.update(key);
1268
1283
  }
1269
1284
  }
1270
1285
  }
@@ -1413,203 +1428,53 @@ function getElement(origin) {
1413
1428
  if (origin instanceof Element) return origin;
1414
1429
  return origin instanceof Event && origin.target instanceof Element ? origin.target : void 0;
1415
1430
  }
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
1431
  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 });
1432
+ constructor(state) {
1433
+ this.state = state;
1434
+ mapped$1.set(state.element, this);
1589
1435
  }
1590
1436
  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
- }
1437
+ mapped$1.delete(this.state.element);
1438
+ this.state = void 0;
1605
1439
  }
1606
1440
  onSort(event, target) {
1607
- const { managers } = this;
1608
1441
  const direction = target.getAttribute("data-sort-direction");
1609
1442
  const field = target.getAttribute("data-field");
1610
- if (field != null) managers.sort.toggle(event, field, direction);
1443
+ if (field != null) this.state.managers.sort.toggle(event, field, direction);
1611
1444
  }
1612
1445
  };
1446
+ function onClick(event) {
1447
+ const target = findAncestor(event, "[data-event]");
1448
+ const table = findAncestor(event, ".tabela");
1449
+ if (!(target instanceof HTMLElement) || !(table instanceof HTMLElement)) return;
1450
+ const manager = mapped$1.get(table);
1451
+ if (manager == null) return;
1452
+ switch (target?.getAttribute("data-event")) {
1453
+ case "heading":
1454
+ manager.onSort(event, target);
1455
+ break;
1456
+ case "row":
1457
+ manager.state.managers.selection.handle(event, target);
1458
+ break;
1459
+ default: break;
1460
+ }
1461
+ }
1462
+ function onKeydown(event) {
1463
+ const target = findAncestor(event, "[data-event]");
1464
+ const table = findAncestor(event, ".tabela");
1465
+ if (!(target instanceof HTMLElement) || !(table instanceof HTMLElement)) return;
1466
+ const manager = mapped$1.get(table);
1467
+ if (manager == null) return;
1468
+ switch (target?.getAttribute("data-event")) {
1469
+ case "body":
1470
+ manager.state.managers.navigation.handle(event);
1471
+ break;
1472
+ default: break;
1473
+ }
1474
+ }
1475
+ const mapped$1 = /* @__PURE__ */ new WeakMap();
1476
+ on(document, "click", onClick);
1477
+ on(document, "keydown", onKeydown, { passive: false });
1613
1478
  /**
1614
1479
  * Clamp a number between a minimum and maximum value
1615
1480
  * @param value Value to clamp
@@ -2014,8 +1879,8 @@ var FilterManager = class {
2014
1879
  set: (items) => this.set(items)
2015
1880
  });
2016
1881
  items = {};
2017
- constructor(managers) {
2018
- this.managers = managers;
1882
+ constructor(state) {
1883
+ this.state = state;
2019
1884
  }
2020
1885
  add(item) {
2021
1886
  if (this.items[item.field] == null) this.items[item.field] = [];
@@ -2031,16 +1896,17 @@ var FilterManager = class {
2031
1896
  }
2032
1897
  destroy() {
2033
1898
  this.handlers = void 0;
2034
- this.items = {};
1899
+ this.items = void 0;
1900
+ this.state = void 0;
2035
1901
  }
2036
1902
  filter() {
2037
- const { managers } = this;
1903
+ const { state } = this;
2038
1904
  const filtered = [];
2039
1905
  const filters = Object.entries(this.items);
2040
- const keysLength = managers.data.values.keys.original.length;
1906
+ const keysLength = state.managers.data.values.keys.original.length;
2041
1907
  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);
1908
+ const key = state.managers.data.values.keys.original[keyIndex];
1909
+ const row = state.managers.data.values.objects.mapped.get(key);
2044
1910
  if (row == null) continue;
2045
1911
  filterLoop: for (let filterIndex = 0; filterIndex < filters.length; filterIndex += 1) {
2046
1912
  const [field, items] = filters[filterIndex];
@@ -2053,9 +1919,9 @@ var FilterManager = class {
2053
1919
  }
2054
1920
  filtered.push(key);
2055
1921
  }
2056
- managers.data.values.keys.active = filtered;
2057
- if (managers.sort.items.length > 0) managers.sort.sort();
2058
- else managers.render.update(true, true);
1922
+ state.managers.data.values.keys.active = filtered;
1923
+ if (state.managers.sort.items.length > 0) state.managers.sort.sort();
1924
+ else state.managers.render.update(true, true);
2059
1925
  }
2060
1926
  remove(value) {
2061
1927
  if (typeof value === "string") {
@@ -2093,6 +1959,81 @@ const comparators = {
2093
1959
  "starts-with": (row, filter) => startsWith(getString(row), getString(filter), true)
2094
1960
  };
2095
1961
  const equalizer = equal.initialize({ ignoreCase: true });
1962
+ function getKey(value) {
1963
+ if (typeof value === "number") return value;
1964
+ if (typeof value !== "string") return;
1965
+ return integerExpression.test(value) ? Number.parseInt(value, 10) : value;
1966
+ }
1967
+ const integerExpression = /^\d+$/;
1968
+ var NavigationManager = class {
1969
+ active;
1970
+ constructor(state) {
1971
+ this.state = state;
1972
+ }
1973
+ destroy() {
1974
+ this.state = void 0;
1975
+ }
1976
+ handle(event) {
1977
+ if (!allKeys.has(event.key)) return;
1978
+ event.preventDefault();
1979
+ const { components, id, managers } = this.state;
1980
+ const activeDescendant = components.body.elements.group.getAttribute("aria-activedescendant");
1981
+ const keys = managers.data.values.keys.active ?? managers.data.values.keys.original;
1982
+ const { length } = keys;
1983
+ let next;
1984
+ if (isNullableOrWhitespace(activeDescendant)) next = getDefaultIndex(event.key, length);
1985
+ else next = getIndex(event, activeDescendant, id, keys);
1986
+ if (next != null) this.setActive(keys.at(next));
1987
+ }
1988
+ setActive(key, scroll) {
1989
+ const { components, managers, options } = this.state;
1990
+ this.active = key;
1991
+ const active = components.body.elements.group.querySelectorAll("[data-active=\"true\"]");
1992
+ for (const item of active) item.setAttribute("data-active", "false");
1993
+ const row = managers.row.get(key);
1994
+ if (row != null) {
1995
+ row.element?.setAttribute("data-active", "true");
1996
+ if (scroll ?? true) if (row.element == null) components.body.elements.group.scrollTo({
1997
+ top: managers.data.getIndex(key) * options.rowHeight,
1998
+ behavior: "smooth"
1999
+ });
2000
+ else row.element.scrollIntoView({ block: "nearest" });
2001
+ }
2002
+ components.body.elements.group.setAttribute("aria-activedescendant", row == null ? "" : `tabela_${this.state.id}_row_${key}`);
2003
+ }
2004
+ };
2005
+ function getDefaultIndex(key, max) {
2006
+ switch (true) {
2007
+ case negativeDefaultKeys.has(key): return -1;
2008
+ case key === "PageDown": return Math.min(9, max - 1);
2009
+ case key === "PageUp": return max < 10 ? 0 : max - 10;
2010
+ default: return 0;
2011
+ }
2012
+ }
2013
+ function getIndex(event, active, id, keys) {
2014
+ const key = getKey(active.replace(`tabela_${id}_row_`, ""));
2015
+ if (key == null) return;
2016
+ if (absoluteKeys.has(event.key)) return event.key === "Home" ? 0 : keys.length - 1;
2017
+ return clamp(keys.indexOf(key) + getOffset(event.key), 0, keys.length - 1, true);
2018
+ }
2019
+ function getOffset(key) {
2020
+ switch (key) {
2021
+ case "ArrowDown": return 1;
2022
+ case "ArrowUp": return -1;
2023
+ case "PageDown": return 10;
2024
+ case "PageUp": return -10;
2025
+ default: return 0;
2026
+ }
2027
+ }
2028
+ const absoluteKeys = new Set(["End", "Home"]);
2029
+ const arrowKeys = new Set(["ArrowDown", "ArrowUp"]);
2030
+ const negativeDefaultKeys = new Set(["ArrowUp", "End"]);
2031
+ const pageKeys = new Set(["PageDown", "PageUp"]);
2032
+ const allKeys = new Set([
2033
+ ...absoluteKeys,
2034
+ ...arrowKeys,
2035
+ ...pageKeys
2036
+ ]);
2096
2037
  function removeRow(pool, row) {
2097
2038
  if (row.element != null) {
2098
2039
  row.element.innerHTML = "";
@@ -2102,27 +2043,30 @@ function removeRow(pool, row) {
2102
2043
  }
2103
2044
  row.cells = {};
2104
2045
  }
2105
- function renderRow(managers, row) {
2106
- const element = row.element ?? managers.render.pool.rows.shift() ?? createRow();
2046
+ function renderRow(state, row) {
2047
+ const element = row.element ?? state.managers.render.pool.rows.shift() ?? createRow();
2107
2048
  row.element = element;
2108
2049
  element.innerHTML = "";
2109
- const selected = managers.selection.items.has(row.key);
2050
+ const selected = state.managers.selection.items.has(row.key);
2051
+ const key = String(row.key);
2110
2052
  setAttributes(element, {
2111
2053
  "aria-selected": String(selected),
2054
+ "data-active": String(state.managers.navigation.active === row.key),
2112
2055
  "data-event": "row",
2113
- "data-key": String(row.key)
2056
+ "data-key": key,
2057
+ id: `tabela_${state.id}_row_${key}`
2114
2058
  });
2115
2059
  element.classList.add("tabela__row--body");
2116
2060
  if (selected) element.classList.add("tabela__row--selected");
2117
2061
  else element.classList.remove("tabela__row--selected");
2118
- const columns = managers.column.items;
2062
+ const columns = state.managers.column.items;
2119
2063
  const { length } = columns;
2120
- const data = managers.data.values.objects.mapped.get(row.key);
2064
+ const data = state.managers.data.values.objects.mapped.get(row.key);
2121
2065
  if (data == null) return;
2122
2066
  for (let index = 0; index < length; index += 1) {
2123
2067
  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);
2068
+ state.managers.render.pool.cells[options.field] ??= [];
2069
+ const cell = state.managers.render.pool.cells[columns[index].options.field].shift() ?? createCell(options.width);
2126
2070
  cell.textContent = String(data[options.field]);
2127
2071
  row.cells[options.field] = cell;
2128
2072
  element.append(cell);
@@ -2135,48 +2079,315 @@ var RowComponent = class {
2135
2079
  this.key = key;
2136
2080
  }
2137
2081
  };
2138
- var RowManager = class {
2139
- components = /* @__PURE__ */ new Map();
2140
- height;
2141
- constructor(managers, rowHeight) {
2142
- this.managers = managers;
2143
- this.height = rowHeight;
2144
- }
2145
- destroy() {
2146
- const components = [...this.components.values()];
2147
- const { length } = components;
2148
- for (let index = 0; index < length; index += 1) removeRow(this.managers.render.pool, components[index]);
2149
- this.components.clear();
2082
+ function getRange(down) {
2083
+ const { components, managers, options } = this.state;
2084
+ const { clientHeight, scrollTop } = components.body.elements.group;
2085
+ 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);
2087
+ const before = Math.ceil(clientHeight / options.rowHeight) * (down ? 1 : 2);
2088
+ const after = Math.ceil(clientHeight / options.rowHeight) * (down ? 2 : 1);
2089
+ const start = Math.max(0, first - before);
2090
+ return {
2091
+ end: Math.min((managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length) - 1, last + after),
2092
+ start
2093
+ };
2094
+ }
2095
+ function onScroll() {
2096
+ const { state } = this;
2097
+ if (!state.active) {
2098
+ requestAnimationFrame(() => {
2099
+ const top = state.components.body.elements.group.scrollTop;
2100
+ this.update(top > state.top);
2101
+ state.active = false;
2102
+ state.top = top;
2103
+ });
2104
+ state.active = true;
2150
2105
  }
2151
- get(key) {
2152
- let row = this.components.get(key);
2153
- if (row == null) {
2154
- row = new RowComponent(key);
2155
- this.components.set(key, row);
2156
- }
2157
- return row;
2106
+ }
2107
+ var RenderManager = class {
2108
+ fragment;
2109
+ listener;
2110
+ pool = {
2111
+ cells: {},
2112
+ rows: []
2113
+ };
2114
+ state;
2115
+ visible = /* @__PURE__ */ new Map();
2116
+ constructor(state) {
2117
+ this.listener = on(state.components.body.elements.group, "scroll", onScroll.bind(this));
2118
+ this.state = {
2119
+ ...state,
2120
+ active: false,
2121
+ top: 0
2122
+ };
2158
2123
  }
2159
- has(key) {
2160
- return this.components.has(key);
2124
+ destroy() {
2125
+ const { listener, pool, visible } = this;
2126
+ listener();
2127
+ visible.clear();
2128
+ pool.cells = {};
2129
+ pool.rows = [];
2130
+ this.fragment = void 0;
2131
+ this.listener = void 0;
2132
+ this.pool = void 0;
2133
+ this.state = void 0;
2134
+ this.visible = void 0;
2161
2135
  }
2162
- remove(key) {
2136
+ removeCells(fields) {
2137
+ const { pool, state, visible } = this;
2138
+ const { length } = fields;
2139
+ for (let index = 0; index < length; index += 1) delete pool.cells[fields[index]];
2140
+ for (const [, key] of visible) {
2141
+ const row = state.managers.row.get(key);
2142
+ if (row == null || row.element == null) continue;
2143
+ for (let index = 0; index < length; index += 1) {
2144
+ row.cells[fields[index]].innerHTML = "";
2145
+ row.cells[fields[index]].remove();
2146
+ delete row.cells[fields[index]];
2147
+ }
2148
+ }
2149
+ }
2150
+ getFragment() {
2151
+ this.fragment ??= document.createDocumentFragment();
2152
+ this.fragment.replaceChildren();
2153
+ return this.fragment;
2154
+ }
2155
+ update(down, rerender) {
2156
+ const { state, pool, visible } = this;
2157
+ const { components, managers, options } = state;
2158
+ components.body.elements.faker.style.height = `${managers.data.size * options.rowHeight}px`;
2159
+ const indices = /* @__PURE__ */ new Set();
2160
+ const range = getRange.call(this, down);
2161
+ for (let index = range.start; index <= range.end; index += 1) indices.add(index);
2162
+ let remove = rerender ?? false;
2163
+ for (const [index, key] of visible) {
2164
+ const row = managers.row.get(key);
2165
+ if (remove || row == null || !indices.has(index)) {
2166
+ visible.delete(index);
2167
+ if (row != null) removeRow(pool, row);
2168
+ }
2169
+ }
2170
+ const fragment = this.getFragment();
2171
+ const keys = managers.data.values.keys.active ?? managers.data.values.keys.original;
2172
+ let count = 0;
2173
+ for (let index = range.start; index <= range.end; index += 1) {
2174
+ if (visible.has(index)) continue;
2175
+ const key = keys[index];
2176
+ const row = managers.row.get(key);
2177
+ if (row == null) continue;
2178
+ count += 1;
2179
+ renderRow(state, row);
2180
+ visible.set(index, key);
2181
+ if (row.element != null) {
2182
+ row.element.style.transform = `translateY(${index * options.rowHeight}px)`;
2183
+ fragment.append(row.element);
2184
+ }
2185
+ }
2186
+ if (count > 0) components.body.elements.group[down ? "append" : "prepend"](fragment);
2187
+ }
2188
+ };
2189
+ var RowManager = class {
2190
+ components = /* @__PURE__ */ new Map();
2191
+ constructor(state) {
2192
+ this.state = state;
2193
+ }
2194
+ destroy() {
2195
+ const components = [...this.components.values()];
2196
+ const { length } = components;
2197
+ for (let index = 0; index < length; index += 1) removeRow(this.state.managers.render.pool, components[index]);
2198
+ this.components.clear();
2199
+ this.components = void 0;
2200
+ this.state = void 0;
2201
+ }
2202
+ get(key) {
2203
+ let row = this.components.get(key);
2204
+ if (row == null) {
2205
+ row = new RowComponent(key);
2206
+ this.components.set(key, row);
2207
+ }
2208
+ return row;
2209
+ }
2210
+ has(key) {
2211
+ return this.components.has(key);
2212
+ }
2213
+ remove(key) {
2163
2214
  const row = this.components.get(key);
2164
2215
  if (row != null) {
2165
- removeRow(this.managers.render.pool, row);
2216
+ removeRow(this.state.managers.render.pool, row);
2166
2217
  this.components.delete(key);
2167
2218
  }
2168
2219
  }
2169
2220
  update(key) {
2170
2221
  const row = this.components.get(key);
2171
- if (row != null) renderRow(this.managers, row);
2222
+ if (row != null) renderRow(this.state, row);
2172
2223
  }
2173
2224
  };
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;
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
+ });
2178
2230
  }
2179
- const integerExpression = /^\d+$/;
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
+ })();
2180
2391
  const dragStyling = toggleStyles(document.body, {
2181
2392
  userSelect: "none",
2182
2393
  webkitUserSelect: "none"
@@ -2190,10 +2401,9 @@ var SelectionManager = class {
2190
2401
  });
2191
2402
  items = /* @__PURE__ */ new Set();
2192
2403
  last;
2193
- constructor(element, managers) {
2194
- this.element = element;
2195
- this.managers = managers;
2196
- mapped.set(element, this);
2404
+ constructor(state) {
2405
+ this.state = state;
2406
+ mapped.set(state.element, this);
2197
2407
  }
2198
2408
  clear() {
2199
2409
  if (this.items.size === 0) return;
@@ -2211,48 +2421,47 @@ var SelectionManager = class {
2211
2421
  if (removed.length > 0) this.update(removed);
2212
2422
  }
2213
2423
  destroy() {
2214
- mapped.delete(this.element);
2424
+ mapped.delete(this.state.element);
2215
2425
  this.handlers = void 0;
2216
- this.element = void 0;
2217
2426
  this.items = void 0;
2427
+ this.last = void 0;
2428
+ this.state = void 0;
2218
2429
  }
2219
2430
  handle(event, target) {
2220
2431
  const key = getKey(target.getAttribute("data-key"));
2221
2432
  if (key == null) return;
2222
2433
  const { items } = this;
2223
2434
  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;
2435
+ if (this.last == null) this.state.managers.navigation.setActive(key, false);
2436
+ else this.range(this.last, key);
2230
2437
  return;
2231
2438
  }
2232
2439
  this.last = key;
2440
+ this.state.managers.navigation.setActive(key, false);
2233
2441
  if (event.ctrlKey || event.metaKey) {
2234
2442
  if (items.has(key)) this.deselect([key]);
2235
2443
  else this.select([key]);
2236
2444
  return;
2237
2445
  }
2238
- if (items.has(key)) if (items.size === 1) this.clear();
2239
- else this.set([key]);
2240
- else this.set([key]);
2446
+ this.set([key]);
2241
2447
  }
2242
2448
  range(from, to) {
2449
+ const { state } = this;
2243
2450
  const keyed = isKey(from) && isKey(to);
2244
2451
  const fromKey = keyed ? from : getKey(from.getAttribute("data-key"));
2245
2452
  const toKey = keyed ? to : getKey(to.getAttribute("data-key"));
2246
2453
  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);
2454
+ const keys = state.managers.data.values.keys.active ?? state.managers.data.values.keys.original;
2455
+ const fromIndex = state.managers.data.getIndex(fromKey);
2456
+ const toIndex = state.managers.data.getIndex(toKey);
2250
2457
  if (fromIndex === -1 || toIndex === -1) return;
2251
2458
  const [start, end] = fromIndex < toIndex ? [fromIndex, toIndex] : [toIndex, fromIndex];
2252
2459
  const selected = [];
2253
2460
  for (let index = start; index <= end; index += 1) selected.push(keys[index]);
2254
2461
  if (keyed) this.select(selected);
2255
2462
  else this.set(selected);
2463
+ this.last = toKey;
2464
+ this.state.managers.navigation.setActive(toKey, false);
2256
2465
  }
2257
2466
  select(keys) {
2258
2467
  const { length } = keys;
@@ -2275,8 +2484,8 @@ var SelectionManager = class {
2275
2484
  this.update(removed);
2276
2485
  }
2277
2486
  toggle() {
2278
- const { items, managers } = this;
2279
- const all = managers.data.values.keys.active ?? managers.data.values.keys.original;
2487
+ const { items, state } = this;
2488
+ const all = state.managers.data.values.keys.active ?? state.managers.data.values.keys.original;
2280
2489
  if (items.size === all.length) this.clear();
2281
2490
  else this.select(all);
2282
2491
  }
@@ -2291,7 +2500,7 @@ var SelectionManager = class {
2291
2500
  const { length } = items;
2292
2501
  for (let index = 0; index < length; index += 1) {
2293
2502
  const { key, removed } = items[index];
2294
- const row = this.managers.row.get(key);
2503
+ const row = this.state.managers.row.get(key);
2295
2504
  if (row == null || row.element == null) continue;
2296
2505
  setAttribute(row.element, "aria-selected", String(!removed));
2297
2506
  if (removed) row.element.classList.remove("tabela__row--selected");
@@ -2373,8 +2582,8 @@ var SortManager = class {
2373
2582
  set: (items) => this.set(items)
2374
2583
  });
2375
2584
  items = [];
2376
- constructor(managers) {
2377
- this.managers = managers;
2585
+ constructor(state) {
2586
+ this.state = state;
2378
2587
  }
2379
2588
  add(field, direction) {
2380
2589
  if (this.items.findIndex((item) => item.key === field) > -1) return;
@@ -2399,7 +2608,8 @@ var SortManager = class {
2399
2608
  }
2400
2609
  destroy() {
2401
2610
  this.handlers = void 0;
2402
- this.items.length = 0;
2611
+ this.items = void 0;
2612
+ this.state = void 0;
2403
2613
  }
2404
2614
  flip(field) {
2405
2615
  const item = this.items.find((item) => item.key === field);
@@ -2426,10 +2636,10 @@ var SortManager = class {
2426
2636
  this.sort();
2427
2637
  }
2428
2638
  sort() {
2429
- const { items, managers } = this;
2430
- const { length } = managers.column.items;
2639
+ const { items, state } = this;
2640
+ const { length } = state.managers.column.items;
2431
2641
  for (let index = 0; index < length; index += 1) {
2432
- const column = managers.column.items[index];
2642
+ const column = state.managers.column.items[index];
2433
2643
  const sorterIndex = items.findIndex((item) => item.key === column.options.field);
2434
2644
  const sorterItem = items[sorterIndex];
2435
2645
  setAttributes(column.elements.wrapper, {
@@ -2438,8 +2648,8 @@ var SortManager = class {
2438
2648
  });
2439
2649
  setAttribute(column.elements.sorter, "data-sort-position", sorterIndex > -1 && items.length > 1 ? sorterIndex + 1 : void 0);
2440
2650
  }
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);
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);
2443
2653
  }
2444
2654
  toggle(event, field, direction) {
2445
2655
  switch (direction) {
@@ -2455,108 +2665,6 @@ var SortManager = class {
2455
2665
  }
2456
2666
  }
2457
2667
  };
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
2668
  var Tabela = class {
2561
2669
  #components = {
2562
2670
  header: void 0,
@@ -2564,12 +2672,14 @@ var Tabela = class {
2564
2672
  footer: void 0
2565
2673
  };
2566
2674
  #element;
2675
+ #id = getId();
2567
2676
  #key;
2568
2677
  #managers = {
2569
2678
  column: void 0,
2570
2679
  data: void 0,
2571
2680
  event: void 0,
2572
2681
  filter: void 0,
2682
+ navigation: void 0,
2573
2683
  render: void 0,
2574
2684
  row: void 0,
2575
2685
  selection: void 0,
@@ -2592,14 +2702,23 @@ var Tabela = class {
2592
2702
  this.#components.header = new HeaderComponent();
2593
2703
  this.#components.body = new BodyComponent();
2594
2704
  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);
2705
+ const state = {
2706
+ element,
2707
+ options,
2708
+ components: this.#components,
2709
+ id: this.#id,
2710
+ key: this.#key,
2711
+ managers: this.#managers
2712
+ };
2713
+ this.#managers.column = new ColumnManager(state);
2714
+ this.#managers.data = new DataManager(state);
2715
+ this.#managers.event = new EventManager(state);
2716
+ this.#managers.filter = new FilterManager(state);
2717
+ this.#managers.navigation = new NavigationManager(state);
2718
+ this.#managers.render = new RenderManager(state);
2719
+ this.#managers.row = new RowManager(state);
2720
+ this.#managers.selection = new SelectionManager(state);
2721
+ this.#managers.sort = new SortManager(state);
2603
2722
  element.append(this.#components.header.elements.group, this.#components.body.elements.group, this.#components.footer.elements.group);
2604
2723
  this.#managers.data.set(options.data);
2605
2724
  this.data = this.#managers.data.handlers;
@@ -2620,6 +2739,7 @@ var Tabela = class {
2620
2739
  managers.filter.destroy();
2621
2740
  managers.render.destroy();
2622
2741
  managers.row.destroy();
2742
+ managers.selection.destroy();
2623
2743
  managers.sort.destroy();
2624
2744
  element.innerHTML = "";
2625
2745
  element.role = "";
@@ -2629,6 +2749,11 @@ var Tabela = class {
2629
2749
  this.#element = void 0;
2630
2750
  }
2631
2751
  };
2752
+ function getId() {
2753
+ id += 1;
2754
+ return id;
2755
+ }
2756
+ let id = 0;
2632
2757
  function tabela(element, options) {
2633
2758
  return new Tabela(element, options);
2634
2759
  }