@oscarpalmer/tabela 0.9.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 (60) hide show
  1. package/dist/components/body.component.js +3 -15
  2. package/dist/components/footer.component.js +3 -3
  3. package/dist/components/header.component.js +2 -2
  4. package/dist/components/row.component.js +19 -7
  5. package/dist/helpers/dom.helpers.js +5 -10
  6. package/dist/helpers/misc.helpers.js +7 -0
  7. package/dist/helpers/style.helper.js +6 -0
  8. package/dist/managers/column.manager.js +10 -9
  9. package/dist/managers/data.manager.js +26 -22
  10. package/dist/managers/event.manager.js +39 -19
  11. package/dist/managers/filter.manager.js +11 -10
  12. package/dist/managers/navigation.manager.js +73 -0
  13. package/dist/managers/render.manager.js +110 -0
  14. package/dist/managers/row.manager.js +7 -7
  15. package/dist/managers/selection.manager.js +189 -0
  16. package/dist/managers/sort.manager.js +9 -8
  17. package/dist/tabela.full.js +1096 -433
  18. package/dist/tabela.js +34 -11
  19. package/package.json +1 -1
  20. package/src/components/body.component.ts +5 -20
  21. package/src/components/footer.component.ts +3 -3
  22. package/src/components/header.component.ts +2 -2
  23. package/src/components/row.component.ts +30 -10
  24. package/src/helpers/dom.helpers.ts +3 -10
  25. package/src/helpers/misc.helpers.ts +15 -0
  26. package/src/helpers/style.helper.ts +6 -0
  27. package/src/managers/column.manager.ts +12 -14
  28. package/src/managers/data.manager.ts +31 -27
  29. package/src/managers/event.manager.ts +67 -37
  30. package/src/managers/filter.manager.ts +12 -11
  31. package/src/managers/navigation.manager.ts +145 -0
  32. package/src/managers/render.manager.ts +184 -0
  33. package/src/managers/row.manager.ts +9 -14
  34. package/src/managers/selection.manager.ts +332 -0
  35. package/src/managers/sort.manager.ts +14 -14
  36. package/src/models/render.model.ts +16 -0
  37. package/src/models/tabela.model.ts +23 -2
  38. package/src/tabela.ts +42 -10
  39. package/types/components/row.component.d.ts +4 -4
  40. package/types/helpers/dom.helpers.d.ts +1 -1
  41. package/types/helpers/misc.helpers.d.ts +2 -0
  42. package/types/helpers/style.helper.d.ts +1 -0
  43. package/types/managers/column.manager.d.ts +4 -5
  44. package/types/managers/data.manager.d.ts +5 -6
  45. package/types/managers/event.manager.d.ts +3 -6
  46. package/types/managers/filter.manager.d.ts +3 -3
  47. package/types/managers/navigation.manager.d.ts +10 -0
  48. package/types/managers/render.manager.d.ts +16 -0
  49. package/types/managers/row.manager.d.ts +4 -5
  50. package/types/managers/selection.manager.d.ts +18 -0
  51. package/types/managers/sort.manager.d.ts +4 -4
  52. package/types/models/render.model.d.ts +13 -0
  53. package/types/models/tabela.model.d.ts +21 -2
  54. package/types/tabela.d.ts +2 -1
  55. package/dist/managers/virtualization.manager.js +0 -101
  56. package/src/managers/virtualization.manager.ts +0 -176
  57. package/src/models/virtualization.model.ts +0 -14
  58. package/types/managers/virtualization.manager.d.ts +0 -18
  59. package/types/models/virtualization.model.d.ts +0 -12
  60. /package/dist/models/{virtualization.model.js → render.model.js} +0 -0
@@ -1,14 +1,6 @@
1
1
  import { createElement, createRowGroup } from "../helpers/dom.helpers.js";
2
- import { setStyles } from "@oscarpalmer/toretto/style";
3
2
  function createFaker() {
4
- return createElement("div", {}, {}, {
5
- height: "0",
6
- inset: "0 auto auto 0",
7
- opacity: "0",
8
- pointerEvents: "none",
9
- position: "absolute",
10
- width: "1px"
11
- });
3
+ return createElement("div", { className: "tabela__faker" }, {}, {});
12
4
  }
13
5
  var BodyComponent = class {
14
6
  elements = {
@@ -18,13 +10,9 @@ var BodyComponent = class {
18
10
  constructor() {
19
11
  const group = createRowGroup(false);
20
12
  this.elements.group = group;
21
- group.className += " tabela__rowgroup-body";
13
+ group.className += " tabela__rowgroup--body";
22
14
  group.tabIndex = 0;
23
- setStyles(group, {
24
- height: "100%",
25
- overflow: "auto",
26
- position: "relative"
27
- });
15
+ group.setAttribute("data-event", "body");
28
16
  group.append(this.elements.faker);
29
17
  }
30
18
  destroy() {
@@ -8,8 +8,8 @@ var FooterComponent = class {
8
8
  row,
9
9
  cells: []
10
10
  };
11
- group.className += " tabela__rowgroup-footer";
12
- row.className += " tabela__row-footer";
11
+ group.className += " tabela__rowgroup--footer";
12
+ row.className += " tabela__row--footer";
13
13
  }
14
14
  destroy() {
15
15
  this.elements.cells.length = 0;
@@ -23,7 +23,7 @@ var FooterComponent = class {
23
23
  elements.row.innerHTML = "";
24
24
  for (let index = 0; index < length; index += 1) {
25
25
  const cell = createCell(columns[index].options.width ?? 4, false);
26
- cell.className += " tabela__cell-footer";
26
+ cell.className += " tabela__cell--footer";
27
27
  cell.innerHTML = "&nbsp;";
28
28
  elements.cells.push(cell);
29
29
  elements.row.append(cell);
@@ -7,8 +7,8 @@ var HeaderComponent = class {
7
7
  group,
8
8
  row
9
9
  };
10
- group.className += " tabela__rowgroup-header";
11
- row.className += " tabela__row-header";
10
+ group.className += " tabela__rowgroup--header";
11
+ row.className += " tabela__row--header";
12
12
  }
13
13
  destroy() {
14
14
  this.elements.group = void 0;
@@ -1,4 +1,5 @@
1
1
  import { createCell, createRow } from "../helpers/dom.helpers.js";
2
+ import { setAttributes } from "@oscarpalmer/toretto/attribute";
2
3
  function removeRow(pool, row) {
3
4
  if (row.element != null) {
4
5
  row.element.innerHTML = "";
@@ -8,19 +9,30 @@ function removeRow(pool, row) {
8
9
  }
9
10
  row.cells = {};
10
11
  }
11
- function renderRow(managers, row) {
12
- const element = row.element ?? managers.virtualization.pool.rows.shift() ?? createRow();
12
+ function renderRow(state, row) {
13
+ const element = row.element ?? state.managers.render.pool.rows.shift() ?? createRow();
13
14
  row.element = element;
14
- element.dataset.key = String(row.key);
15
15
  element.innerHTML = "";
16
- const columns = managers.column.items;
16
+ const selected = state.managers.selection.items.has(row.key);
17
+ const key = String(row.key);
18
+ setAttributes(element, {
19
+ "aria-selected": String(selected),
20
+ "data-active": String(state.managers.navigation.active === row.key),
21
+ "data-event": "row",
22
+ "data-key": key,
23
+ id: `tabela_${state.id}_row_${key}`
24
+ });
25
+ element.classList.add("tabela__row--body");
26
+ if (selected) element.classList.add("tabela__row--selected");
27
+ else element.classList.remove("tabela__row--selected");
28
+ const columns = state.managers.column.items;
17
29
  const { length } = columns;
18
- const data = managers.data.values.objects.mapped.get(row.key);
30
+ const data = state.managers.data.values.objects.mapped.get(row.key);
19
31
  if (data == null) return;
20
32
  for (let index = 0; index < length; index += 1) {
21
33
  const { options } = columns[index];
22
- managers.virtualization.pool.cells[options.field] ??= [];
23
- const cell = managers.virtualization.pool.cells[columns[index].options.field].shift() ?? createCell(options.width);
34
+ state.managers.render.pool.cells[options.field] ??= [];
35
+ const cell = state.managers.render.pool.cells[columns[index].options.field].shift() ?? createCell(options.width);
24
36
  cell.textContent = String(data[options.field]);
25
37
  row.cells[options.field] = cell;
26
38
  element.append(cell);
@@ -1,11 +1,11 @@
1
- import { setStyles } from "@oscarpalmer/toretto/style";
2
1
  import { setAttributes } from "@oscarpalmer/toretto/attribute";
2
+ import { setStyles } from "@oscarpalmer/toretto/style";
3
3
  function createCell(width, body) {
4
4
  const cell = createElement("div", {
5
5
  className: "tabela__cell",
6
6
  role: "cell"
7
7
  }, {}, { width: `${width}px` });
8
- if (body ?? true) cell.classList.add("tabela__cell-body");
8
+ if (body ?? true) cell.classList.add("tabela__cell--body");
9
9
  return cell;
10
10
  }
11
11
  function createElement(tagName, properties, attributes, style) {
@@ -22,22 +22,17 @@ function createRowGroup(withRow) {
22
22
  role: "rowgroup"
23
23
  }, {}, {});
24
24
  if (!(withRow ?? true)) return group;
25
- const row = createRow(false);
25
+ const row = createRow();
26
26
  group.append(row);
27
27
  return {
28
28
  group,
29
29
  row
30
30
  };
31
31
  }
32
- function createRow(withStyle) {
33
- const row = createElement("div", {
32
+ function createRow() {
33
+ return createElement("div", {
34
34
  className: "tabela__row",
35
35
  role: "row"
36
36
  }, {}, {});
37
- if (withStyle ?? true) setStyles(row, {
38
- inset: "0 auto auto 0",
39
- position: "absolute"
40
- });
41
- return row;
42
37
  }
43
38
  export { createCell, createElement, createRow, createRowGroup };
@@ -0,0 +1,7 @@
1
+ function getKey(value) {
2
+ if (typeof value === "number") return value;
3
+ if (typeof value !== "string") return;
4
+ return integerExpression.test(value) ? Number.parseInt(value, 10) : value;
5
+ }
6
+ var integerExpression = /^\d+$/;
7
+ export { getKey };
@@ -0,0 +1,6 @@
1
+ import { toggleStyles } from "@oscarpalmer/toretto/style";
2
+ const dragStyling = toggleStyles(document.body, {
3
+ userSelect: "none",
4
+ webkitUserSelect: "none"
5
+ });
6
+ export { dragStyling };
@@ -1,18 +1,19 @@
1
1
  import { ColumnComponent } from "../components/column.component.js";
2
2
  var ColumnManager = class {
3
3
  items = [];
4
- constructor(managers, components, columns) {
5
- this.managers = managers;
6
- this.components = components;
7
- this.set(columns);
4
+ constructor(state) {
5
+ this.state = state;
6
+ this.set(state.options.columns);
8
7
  }
9
8
  destroy() {
10
9
  const { length } = this.items;
11
10
  for (let index = 0; index < length; index += 1) this.items[index].destroy();
12
- this.items.length = 0;
11
+ this.items = void 0;
12
+ this.state = void 0;
13
13
  }
14
14
  remove(value) {
15
- const { components, items, managers } = this;
15
+ const { items, state } = this;
16
+ const { components, managers } = state;
16
17
  const fields = (Array.isArray(value) ? value : [value]).filter((item) => typeof item === "string");
17
18
  const { length } = fields;
18
19
  if (length === 0) return;
@@ -25,11 +26,11 @@ var ColumnManager = class {
25
26
  }
26
27
  components.header.update(items);
27
28
  components.footer.update(items);
28
- managers.virtualization.removeCells(fields);
29
+ managers.render.removeCells(fields);
29
30
  }
30
31
  set(columns) {
31
- const { components, items } = this;
32
- const { footer, header } = components;
32
+ const { items, state } = this;
33
+ const { footer, header } = state.components;
33
34
  items.splice(0, items.length, ...columns.map((column) => new ColumnComponent(column)));
34
35
  header.update(items);
35
36
  footer.update(items);
@@ -20,15 +20,13 @@ var DataManager = class {
20
20
  get size() {
21
21
  return this.values.keys.active?.length ?? this.values.keys.original.length;
22
22
  }
23
- constructor(managers, components, field) {
24
- this.managers = managers;
25
- this.components = components;
26
- this.field = field;
23
+ constructor(state) {
24
+ this.state = state;
27
25
  }
28
26
  async add(data, render) {
29
- const { field, values } = this;
27
+ const { state, values } = this;
30
28
  push(values.objects.array, data);
31
- values.objects.mapped = toMap(values.objects.array, field);
29
+ values.objects.mapped = toMap(values.objects.array, state.key);
32
30
  if (render) this.render();
33
31
  }
34
32
  clear() {
@@ -41,48 +39,54 @@ var DataManager = class {
41
39
  values.keys.original.length = 0;
42
40
  values.objects.array.length = 0;
43
41
  this.handlers = void 0;
42
+ this.state = void 0;
43
+ this.values = void 0;
44
44
  }
45
45
  get(active) {
46
46
  const { values } = this;
47
47
  return active ?? false ? values.keys.active?.map((key) => values.objects.mapped.get(key)) ?? [] : values.objects.array;
48
48
  }
49
+ getIndex(key) {
50
+ const { values } = this;
51
+ return (values.keys.active ?? values.keys.original).indexOf(key);
52
+ }
49
53
  async remove(items, render) {
50
- const { field, managers, values } = this;
51
- const keys = items.map((value) => isPlainObject(value) ? value[field] : value).filter((key) => values.objects.mapped.has(key));
54
+ const { state, values } = this;
55
+ const keys = items.map((value) => isPlainObject(value) ? value[state.key] : value).filter((key) => values.objects.mapped.has(key));
52
56
  const { length } = keys;
53
57
  if (length === 0) return;
54
58
  for (let keyIndex = 0; keyIndex < length; keyIndex += 1) {
55
59
  const key = keys[keyIndex];
56
60
  values.objects.mapped.delete(key);
57
- const arrayIndex = values.objects.array.findIndex((object) => object[field] === key);
61
+ const arrayIndex = values.objects.array.findIndex((object) => object[state.key] === key);
58
62
  if (arrayIndex > -1) values.objects.array.splice(arrayIndex, 1);
59
63
  values.keys.original.splice(values.keys.original.indexOf(key), 1);
60
- managers.row.remove(key);
64
+ state.managers.row.remove(key);
61
65
  }
62
66
  if (render) this.render();
63
67
  }
64
68
  render() {
65
- const { field, managers, values } = this;
66
- values.keys.original = sort(values.objects.array.map((item) => item[field]));
67
- if (Object.keys(managers.filter.items).length > 0) managers.filter.filter();
68
- else if (managers.sort.items.length > 0) managers.sort.sort();
69
- else managers.virtualization.update(true);
69
+ const { state, values } = this;
70
+ values.keys.original = sort(values.objects.array.map((item) => item[state.key]));
71
+ if (Object.keys(state.managers.filter.items).length > 0) state.managers.filter.filter();
72
+ else if (state.managers.sort.items.length > 0) state.managers.sort.sort();
73
+ else state.managers.render.update(true);
70
74
  }
71
75
  set(data) {
72
- const { field, values } = this;
73
- values.objects.mapped = toMap(data, field);
76
+ const { state, values } = this;
77
+ values.objects.mapped = toMap(data, state.key);
74
78
  values.objects.array = data;
75
79
  this.render();
76
80
  }
77
81
  async synchronize(data, remove) {
78
- const { field, values } = this;
82
+ const { state, values } = this;
79
83
  const add = [];
80
84
  const updated = [];
81
85
  const keys = /* @__PURE__ */ new Set([]);
82
86
  const { length } = data;
83
87
  for (let index = 0; index < length; index += 1) {
84
88
  const object = data[index];
85
- const key = object[field];
89
+ const key = object[state.key];
86
90
  if (values.objects.mapped.has(key)) updated.push(object);
87
91
  else add.push(object);
88
92
  keys.add(key);
@@ -97,18 +101,18 @@ var DataManager = class {
97
101
  if (add.length > 0 || (remove ?? false)) this.render();
98
102
  }
99
103
  async update(data) {
100
- const { field, managers, values } = this;
104
+ const { state, values } = this;
101
105
  const { length } = data;
102
106
  for (let index = 0; index < length; index += 1) {
103
107
  const object = data[index];
104
- const key = object[field];
108
+ const key = object[state.key];
105
109
  const value = values.objects.mapped.get(key);
106
110
  if (value != null) {
107
111
  values.objects.mapped.set(key, {
108
112
  ...value,
109
113
  ...object
110
114
  });
111
- managers.row.update(key);
115
+ state.managers.row.update(key);
112
116
  }
113
117
  }
114
118
  }
@@ -1,30 +1,50 @@
1
1
  import { on } from "@oscarpalmer/toretto/event";
2
- import { findAncestor } from "@oscarpalmer/toretto";
2
+ import { findAncestor } from "@oscarpalmer/toretto/find";
3
3
  var EventManager = class {
4
- listener;
5
- constructor(managers, element) {
6
- this.managers = managers;
7
- this.listener = on(element, "click", (event) => {
8
- this.onClick(event);
9
- }, { passive: false });
4
+ constructor(state) {
5
+ this.state = state;
6
+ mapped.set(state.element, this);
10
7
  }
11
8
  destroy() {
12
- this.listener();
13
- }
14
- onClick(event) {
15
- const target = findAncestor(event, "[data-event]");
16
- if (!(target instanceof HTMLElement)) return;
17
- switch (target?.getAttribute("data-event")) {
18
- case "heading":
19
- this.onSort(event, target);
20
- break;
21
- }
9
+ mapped.delete(this.state.element);
10
+ this.state = void 0;
22
11
  }
23
12
  onSort(event, target) {
24
- const { managers } = this;
25
13
  const direction = target.getAttribute("data-sort-direction");
26
14
  const field = target.getAttribute("data-field");
27
- if (field != null) managers.sort.toggle(event, field, direction);
15
+ if (field != null) this.state.managers.sort.toggle(event, field, direction);
28
16
  }
29
17
  };
18
+ function onClick(event) {
19
+ const target = findAncestor(event, "[data-event]");
20
+ const table = findAncestor(event, ".tabela");
21
+ if (!(target instanceof HTMLElement) || !(table instanceof HTMLElement)) return;
22
+ const manager = mapped.get(table);
23
+ if (manager == null) return;
24
+ switch (target?.getAttribute("data-event")) {
25
+ case "heading":
26
+ manager.onSort(event, target);
27
+ break;
28
+ case "row":
29
+ manager.state.managers.selection.handle(event, target);
30
+ break;
31
+ default: break;
32
+ }
33
+ }
34
+ function onKeydown(event) {
35
+ const target = findAncestor(event, "[data-event]");
36
+ const table = findAncestor(event, ".tabela");
37
+ if (!(target instanceof HTMLElement) || !(table instanceof HTMLElement)) return;
38
+ const manager = mapped.get(table);
39
+ if (manager == null) return;
40
+ switch (target?.getAttribute("data-event")) {
41
+ case "body":
42
+ manager.state.managers.navigation.handle(event);
43
+ break;
44
+ default: break;
45
+ }
46
+ }
47
+ var mapped = /* @__PURE__ */ new WeakMap();
48
+ on(document, "click", onClick);
49
+ on(document, "keydown", onKeydown, { passive: false });
30
50
  export { EventManager };
@@ -10,8 +10,8 @@ var FilterManager = class {
10
10
  set: (items) => this.set(items)
11
11
  });
12
12
  items = {};
13
- constructor(managers) {
14
- this.managers = managers;
13
+ constructor(state) {
14
+ this.state = state;
15
15
  }
16
16
  add(item) {
17
17
  if (this.items[item.field] == null) this.items[item.field] = [];
@@ -27,16 +27,17 @@ var FilterManager = class {
27
27
  }
28
28
  destroy() {
29
29
  this.handlers = void 0;
30
- this.items = {};
30
+ this.items = void 0;
31
+ this.state = void 0;
31
32
  }
32
33
  filter() {
33
- const { managers } = this;
34
+ const { state } = this;
34
35
  const filtered = [];
35
36
  const filters = Object.entries(this.items);
36
- const keysLength = managers.data.values.keys.original.length;
37
+ const keysLength = state.managers.data.values.keys.original.length;
37
38
  rowLoop: for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
38
- const key = managers.data.values.keys.original[keyIndex];
39
- const row = managers.data.values.objects.mapped.get(key);
39
+ const key = state.managers.data.values.keys.original[keyIndex];
40
+ const row = state.managers.data.values.objects.mapped.get(key);
40
41
  if (row == null) continue;
41
42
  filterLoop: for (let filterIndex = 0; filterIndex < filters.length; filterIndex += 1) {
42
43
  const [field, items] = filters[filterIndex];
@@ -49,9 +50,9 @@ var FilterManager = class {
49
50
  }
50
51
  filtered.push(key);
51
52
  }
52
- managers.data.values.keys.active = filtered;
53
- if (managers.sort.items.length > 0) managers.sort.sort();
54
- else managers.virtualization.update(true, true);
53
+ state.managers.data.values.keys.active = filtered;
54
+ if (state.managers.sort.items.length > 0) state.managers.sort.sort();
55
+ else state.managers.render.update(true, true);
55
56
  }
56
57
  remove(value) {
57
58
  if (typeof value === "string") {
@@ -0,0 +1,73 @@
1
+ import { getKey } from "../helpers/misc.helpers.js";
2
+ import { isNullableOrWhitespace } from "@oscarpalmer/atoms/is";
3
+ import { clamp } from "@oscarpalmer/atoms/number";
4
+ var NavigationManager = class {
5
+ active;
6
+ constructor(state) {
7
+ this.state = state;
8
+ }
9
+ destroy() {
10
+ this.state = void 0;
11
+ }
12
+ handle(event) {
13
+ if (!allKeys.has(event.key)) return;
14
+ event.preventDefault();
15
+ const { components, id, managers } = this.state;
16
+ const activeDescendant = components.body.elements.group.getAttribute("aria-activedescendant");
17
+ const keys = managers.data.values.keys.active ?? managers.data.values.keys.original;
18
+ const { length } = keys;
19
+ let next;
20
+ if (isNullableOrWhitespace(activeDescendant)) next = getDefaultIndex(event.key, length);
21
+ else next = getIndex(event, activeDescendant, id, keys);
22
+ if (next != null) this.setActive(keys.at(next));
23
+ }
24
+ setActive(key, scroll) {
25
+ const { components, managers, options } = this.state;
26
+ this.active = key;
27
+ const active = components.body.elements.group.querySelectorAll("[data-active=\"true\"]");
28
+ for (const item of active) item.setAttribute("data-active", "false");
29
+ const row = managers.row.get(key);
30
+ if (row != null) {
31
+ row.element?.setAttribute("data-active", "true");
32
+ if (scroll ?? true) if (row.element == null) components.body.elements.group.scrollTo({
33
+ top: managers.data.getIndex(key) * options.rowHeight,
34
+ behavior: "smooth"
35
+ });
36
+ else row.element.scrollIntoView({ block: "nearest" });
37
+ }
38
+ components.body.elements.group.setAttribute("aria-activedescendant", row == null ? "" : `tabela_${this.state.id}_row_${key}`);
39
+ }
40
+ };
41
+ function getDefaultIndex(key, max) {
42
+ switch (true) {
43
+ case negativeDefaultKeys.has(key): return -1;
44
+ case key === "PageDown": return Math.min(9, max - 1);
45
+ case key === "PageUp": return max < 10 ? 0 : max - 10;
46
+ default: return 0;
47
+ }
48
+ }
49
+ function getIndex(event, active, id, keys) {
50
+ const key = getKey(active.replace(`tabela_${id}_row_`, ""));
51
+ if (key == null) return;
52
+ if (absoluteKeys.has(event.key)) return event.key === "Home" ? 0 : keys.length - 1;
53
+ return clamp(keys.indexOf(key) + getOffset(event.key), 0, keys.length - 1, true);
54
+ }
55
+ function getOffset(key) {
56
+ switch (key) {
57
+ case "ArrowDown": return 1;
58
+ case "ArrowUp": return -1;
59
+ case "PageDown": return 10;
60
+ case "PageUp": return -10;
61
+ default: return 0;
62
+ }
63
+ }
64
+ var absoluteKeys = new Set(["End", "Home"]);
65
+ var arrowKeys = new Set(["ArrowDown", "ArrowUp"]);
66
+ var negativeDefaultKeys = new Set(["ArrowUp", "End"]);
67
+ var pageKeys = new Set(["PageDown", "PageUp"]);
68
+ var allKeys = new Set([
69
+ ...absoluteKeys,
70
+ ...arrowKeys,
71
+ ...pageKeys
72
+ ]);
73
+ export { NavigationManager };
@@ -0,0 +1,110 @@
1
+ import { removeRow, renderRow } from "../components/row.component.js";
2
+ import { on } from "@oscarpalmer/toretto/event";
3
+ function getRange(down) {
4
+ const { components, managers, options } = this.state;
5
+ const { clientHeight, scrollTop } = components.body.elements.group;
6
+ const first = Math.floor(scrollTop / options.rowHeight);
7
+ const last = Math.min((managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length) - 1, Math.ceil((scrollTop + clientHeight) / options.rowHeight) - 1);
8
+ const before = Math.ceil(clientHeight / options.rowHeight) * (down ? 1 : 2);
9
+ const after = Math.ceil(clientHeight / options.rowHeight) * (down ? 2 : 1);
10
+ const start = Math.max(0, first - before);
11
+ return {
12
+ end: Math.min((managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length) - 1, last + after),
13
+ start
14
+ };
15
+ }
16
+ function onScroll() {
17
+ const { state } = this;
18
+ if (!state.active) {
19
+ requestAnimationFrame(() => {
20
+ const top = state.components.body.elements.group.scrollTop;
21
+ this.update(top > state.top);
22
+ state.active = false;
23
+ state.top = top;
24
+ });
25
+ state.active = true;
26
+ }
27
+ }
28
+ var RenderManager = class {
29
+ fragment;
30
+ listener;
31
+ pool = {
32
+ cells: {},
33
+ rows: []
34
+ };
35
+ state;
36
+ visible = /* @__PURE__ */ new Map();
37
+ constructor(state) {
38
+ this.listener = on(state.components.body.elements.group, "scroll", onScroll.bind(this));
39
+ this.state = {
40
+ ...state,
41
+ active: false,
42
+ top: 0
43
+ };
44
+ }
45
+ destroy() {
46
+ const { listener, pool, visible } = this;
47
+ listener();
48
+ visible.clear();
49
+ pool.cells = {};
50
+ pool.rows = [];
51
+ this.fragment = void 0;
52
+ this.listener = void 0;
53
+ this.pool = void 0;
54
+ this.state = void 0;
55
+ this.visible = void 0;
56
+ }
57
+ removeCells(fields) {
58
+ const { pool, state, visible } = this;
59
+ const { length } = fields;
60
+ for (let index = 0; index < length; index += 1) delete pool.cells[fields[index]];
61
+ for (const [, key] of visible) {
62
+ const row = state.managers.row.get(key);
63
+ if (row == null || row.element == null) continue;
64
+ for (let index = 0; index < length; index += 1) {
65
+ row.cells[fields[index]].innerHTML = "";
66
+ row.cells[fields[index]].remove();
67
+ delete row.cells[fields[index]];
68
+ }
69
+ }
70
+ }
71
+ getFragment() {
72
+ this.fragment ??= document.createDocumentFragment();
73
+ this.fragment.replaceChildren();
74
+ return this.fragment;
75
+ }
76
+ update(down, rerender) {
77
+ const { state, pool, visible } = this;
78
+ const { components, managers, options } = state;
79
+ components.body.elements.faker.style.height = `${managers.data.size * options.rowHeight}px`;
80
+ const indices = /* @__PURE__ */ new Set();
81
+ const range = getRange.call(this, down);
82
+ for (let index = range.start; index <= range.end; index += 1) indices.add(index);
83
+ let remove = rerender ?? false;
84
+ for (const [index, key] of visible) {
85
+ const row = managers.row.get(key);
86
+ if (remove || row == null || !indices.has(index)) {
87
+ visible.delete(index);
88
+ if (row != null) removeRow(pool, row);
89
+ }
90
+ }
91
+ const fragment = this.getFragment();
92
+ const keys = managers.data.values.keys.active ?? managers.data.values.keys.original;
93
+ let count = 0;
94
+ for (let index = range.start; index <= range.end; index += 1) {
95
+ if (visible.has(index)) continue;
96
+ const key = keys[index];
97
+ const row = managers.row.get(key);
98
+ if (row == null) continue;
99
+ count += 1;
100
+ renderRow(state, row);
101
+ visible.set(index, key);
102
+ if (row.element != null) {
103
+ row.element.style.transform = `translateY(${index * options.rowHeight}px)`;
104
+ fragment.append(row.element);
105
+ }
106
+ }
107
+ if (count > 0) components.body.elements.group[down ? "append" : "prepend"](fragment);
108
+ }
109
+ };
110
+ export { RenderManager };
@@ -1,16 +1,16 @@
1
1
  import { RowComponent, removeRow, renderRow } from "../components/row.component.js";
2
2
  var RowManager = class {
3
3
  components = /* @__PURE__ */ new Map();
4
- height;
5
- constructor(managers, rowHeight) {
6
- this.managers = managers;
7
- this.height = rowHeight;
4
+ constructor(state) {
5
+ this.state = state;
8
6
  }
9
7
  destroy() {
10
8
  const components = [...this.components.values()];
11
9
  const { length } = components;
12
- for (let index = 0; index < length; index += 1) removeRow(this.managers.virtualization.pool, components[index]);
10
+ for (let index = 0; index < length; index += 1) removeRow(this.state.managers.render.pool, components[index]);
13
11
  this.components.clear();
12
+ this.components = void 0;
13
+ this.state = void 0;
14
14
  }
15
15
  get(key) {
16
16
  let row = this.components.get(key);
@@ -26,13 +26,13 @@ var RowManager = class {
26
26
  remove(key) {
27
27
  const row = this.components.get(key);
28
28
  if (row != null) {
29
- removeRow(this.managers.virtualization.pool, row);
29
+ removeRow(this.state.managers.render.pool, row);
30
30
  this.components.delete(key);
31
31
  }
32
32
  }
33
33
  update(key) {
34
34
  const row = this.components.get(key);
35
- if (row != null) renderRow(this.managers, row);
35
+ if (row != null) renderRow(this.state, row);
36
36
  }
37
37
  };
38
38
  export { RowManager };