@oscarpalmer/tabela 0.6.0 → 0.7.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 (35) hide show
  1. package/dist/components/body.component.js +1 -2
  2. package/dist/components/column.component.js +2 -3
  3. package/dist/components/footer.component.js +1 -2
  4. package/dist/components/header.component.js +1 -2
  5. package/dist/components/row.component.js +7 -7
  6. package/dist/managers/column.manager.js +16 -15
  7. package/dist/managers/data.manager.js +96 -15
  8. package/dist/managers/row.manager.js +13 -3
  9. package/dist/managers/virtualization.manager.js +38 -31
  10. package/dist/models/tabela.model.js +0 -0
  11. package/dist/tabela.full.js +220 -101
  12. package/dist/tabela.js +36 -22
  13. package/package.json +3 -3
  14. package/src/components/body.component.ts +1 -2
  15. package/src/components/column.component.ts +2 -6
  16. package/src/components/footer.component.ts +1 -2
  17. package/src/components/header.component.ts +1 -2
  18. package/src/components/row.component.ts +10 -8
  19. package/src/managers/column.manager.ts +17 -20
  20. package/src/managers/data.manager.ts +161 -20
  21. package/src/managers/row.manager.ts +19 -3
  22. package/src/managers/virtualization.manager.ts +55 -34
  23. package/src/models/tabela.model.ts +31 -0
  24. package/src/tabela.ts +47 -40
  25. package/types/components/body.component.d.ts +1 -3
  26. package/types/components/column.component.d.ts +1 -3
  27. package/types/components/footer.component.d.ts +1 -3
  28. package/types/components/header.component.d.ts +1 -3
  29. package/types/components/row.component.d.ts +3 -3
  30. package/types/managers/column.manager.d.ts +5 -4
  31. package/types/managers/data.manager.d.ts +15 -6
  32. package/types/managers/row.manager.d.ts +6 -3
  33. package/types/managers/virtualization.manager.d.ts +5 -3
  34. package/types/models/tabela.model.d.ts +28 -0
  35. package/types/tabela.d.ts +4 -23
@@ -15,8 +15,7 @@ var BodyComponent = class {
15
15
  faker: createFaker(),
16
16
  group: void 0
17
17
  };
18
- constructor(tabela) {
19
- this.tabela = tabela;
18
+ constructor() {
20
19
  const group = createRowGroup(false);
21
20
  this.elements.group = group;
22
21
  group.className += " tabela__rowgroup-body";
@@ -9,9 +9,8 @@ function createHeading(title, width) {
9
9
  var ColumnComponent = class {
10
10
  element;
11
11
  options;
12
- constructor(tabela, options) {
13
- this.tabela = tabela;
14
- const width = Number.parseInt(getComputedStyle(tabela.element).fontSize, 10) * (options.width ?? options.title.length * 1.5);
12
+ constructor(options) {
13
+ const width = Number.parseInt(getComputedStyle(document.body).fontSize, 10) * (options.width ?? options.title.length * 1.5);
15
14
  this.options = {
16
15
  ...options,
17
16
  width
@@ -1,8 +1,7 @@
1
1
  import { createCell, createRowGroup } from "../helpers/dom.helpers.js";
2
2
  var FooterComponent = class {
3
3
  elements;
4
- constructor(tabela) {
5
- this.tabela = tabela;
4
+ constructor() {
6
5
  const { group, row } = createRowGroup();
7
6
  this.elements = {
8
7
  group,
@@ -1,8 +1,7 @@
1
1
  import { createRowGroup } from "../helpers/dom.helpers.js";
2
2
  var HeaderComponent = class {
3
3
  elements;
4
- constructor(tabela) {
5
- this.tabela = tabela;
4
+ constructor() {
6
5
  const { group, row } = createRowGroup();
7
6
  this.elements = {
8
7
  group,
@@ -1,5 +1,5 @@
1
1
  import { createCell, createRow } from "../helpers/dom.helpers.js";
2
- function removeRow(row, pool) {
2
+ function removeRow(pool, row) {
3
3
  if (row.element != null) {
4
4
  row.element.innerHTML = "";
5
5
  pool.rows.push(row.element);
@@ -8,19 +8,19 @@ function removeRow(row, pool) {
8
8
  }
9
9
  row.cells = {};
10
10
  }
11
- function renderRow(tabela, pool, row) {
12
- const element = row.element ?? pool.rows.shift() ?? createRow();
11
+ function renderRow(managers, row) {
12
+ const element = row.element ?? managers.virtualization.pool.rows.shift() ?? createRow();
13
13
  row.element = element;
14
14
  element.dataset.key = String(row.key);
15
15
  element.innerHTML = "";
16
- const columns = tabela.managers.columns.components;
16
+ const columns = managers.column.items;
17
17
  const { length } = columns;
18
- const data = tabela.managers.data.values.objects.mapped.get(row.key);
18
+ const data = managers.data.values.objects.mapped.get(row.key);
19
19
  if (data == null) return;
20
20
  for (let index = 0; index < length; index += 1) {
21
21
  const { options } = columns[index];
22
- pool.cells[options.field] ??= [];
23
- const cell = pool.cells[columns[index].options.field].shift() ?? createCell(options.width);
22
+ managers.virtualization.pool.cells[options.field] ??= [];
23
+ const cell = managers.virtualization.pool.cells[columns[index].options.field].shift() ?? createCell(options.width);
24
24
  cell.textContent = String(data[options.field]);
25
25
  row.cells[options.field] = cell;
26
26
  element.append(cell);
@@ -1,32 +1,33 @@
1
1
  import { ColumnComponent } from "../components/column.component.js";
2
2
  var ColumnManager = class {
3
- components = [];
4
- constructor(tabela, columns) {
5
- this.tabela = tabela;
3
+ items = [];
4
+ constructor(managers, components, columns) {
5
+ this.managers = managers;
6
+ this.components = components;
6
7
  this.set(columns);
7
8
  }
8
9
  destroy() {
9
- this.components.length = 0;
10
+ this.items.length = 0;
10
11
  }
11
12
  remove(value) {
12
- const { components, tabela } = this;
13
+ const { components, items, managers } = this;
13
14
  const fields = (Array.isArray(value) ? value : [value]).filter((item) => typeof item === "string");
14
15
  const { length } = fields;
15
16
  if (length === 0) return;
16
17
  for (let fieldIndex = 0; fieldIndex < length; fieldIndex += 1) {
17
- const componentIndex = components.findIndex((component) => component.options.field === fields[fieldIndex]);
18
- if (componentIndex > -1) components.splice(componentIndex, 1);
18
+ const itemIndex = items.findIndex((component) => component.options.field === fields[fieldIndex]);
19
+ if (itemIndex > -1) items.splice(itemIndex, 1);
19
20
  }
20
- tabela.components.header.update(components);
21
- tabela.components.footer.update(components);
22
- tabela.managers.virtualization.removeCells(fields);
21
+ components.header.update(items);
22
+ components.footer.update(items);
23
+ managers.virtualization.removeCells(fields);
23
24
  }
24
25
  set(columns) {
25
- const { components, tabela } = this;
26
- const { footer, header } = tabela.components;
27
- components.splice(0, components.length, ...columns.map((column) => new ColumnComponent(tabela, column)));
28
- header.update(components);
29
- footer.update(components);
26
+ const { components, items } = this;
27
+ const { footer, header } = components;
28
+ items.splice(0, items.length, ...columns.map((column) => new ColumnComponent(column)));
29
+ header.update(items);
30
+ footer.update(items);
30
31
  }
31
32
  };
32
33
  export { ColumnManager };
@@ -1,19 +1,38 @@
1
1
  import { toMap } from "@oscarpalmer/atoms/array/to-map";
2
+ import { isPlainObject } from "@oscarpalmer/atoms/is";
2
3
  var DataManager = class {
3
- values;
4
- get length() {
4
+ handlers = Object.freeze({
5
+ add: (data) => void this.add(data, true),
6
+ clear: () => void this.clear(),
7
+ get: (active) => this.get(active),
8
+ remove: (items) => void this.remove(items, true),
9
+ synchronize: (data, remove) => void this.synchronize(data, remove),
10
+ update: (data) => void this.update(data)
11
+ });
12
+ values = {
13
+ keys: { original: [] },
14
+ objects: {
15
+ mapped: /* @__PURE__ */ new Map(),
16
+ array: []
17
+ }
18
+ };
19
+ get size() {
5
20
  return this.values.keys.active?.length ?? this.values.keys.original.length;
6
21
  }
7
- constructor(tabela, values) {
8
- this.tabela = tabela;
9
- const mapped = toMap(values, tabela.key);
10
- this.values = {
11
- keys: { original: [...mapped.keys()] },
12
- objects: {
13
- mapped,
14
- array: values
15
- }
16
- };
22
+ constructor(managers, components, field) {
23
+ this.managers = managers;
24
+ this.components = components;
25
+ this.field = field;
26
+ }
27
+ async add(data, render) {
28
+ const { field, values } = this;
29
+ values.objects.array.push(...data);
30
+ values.objects.mapped = toMap(values.objects.array, field);
31
+ values.keys.original = [...values.objects.mapped.keys()];
32
+ if (render) this.managers.virtualization.update(true);
33
+ }
34
+ clear() {
35
+ if (this.values.objects.array.length > 0) this.set([]);
17
36
  }
18
37
  destroy() {
19
38
  const { values } = this;
@@ -22,9 +41,71 @@ var DataManager = class {
22
41
  values.keys.original.length = 0;
23
42
  values.objects.array.length = 0;
24
43
  }
25
- update() {
26
- this.tabela.components.body.elements.faker.style.height = `${this.length * this.tabela.managers.rows.height}px`;
27
- this.tabela.managers.virtualization.update(true);
44
+ get(active) {
45
+ const { values } = this;
46
+ return active ?? false ? values.keys.active?.map((key) => values.objects.mapped.get(key)) ?? [] : values.objects.array;
47
+ }
48
+ async remove(items, render) {
49
+ const { field, managers, values } = this;
50
+ const keys = items.map((value) => isPlainObject(value) ? value[field] : value).filter((key) => values.objects.mapped.has(key));
51
+ const { length } = keys;
52
+ if (length === 0) return;
53
+ for (let keyIndex = 0; keyIndex < length; keyIndex += 1) {
54
+ const key = keys[keyIndex];
55
+ values.objects.mapped.delete(key);
56
+ const arrayIndex = values.objects.array.findIndex((object) => object[field] === key);
57
+ if (arrayIndex > -1) values.objects.array.splice(arrayIndex, 1);
58
+ values.keys.original.splice(values.keys.original.indexOf(key), 1);
59
+ managers.row.remove(key);
60
+ }
61
+ if (render) this.managers.virtualization.update(true);
62
+ }
63
+ set(data) {
64
+ const { field, values } = this;
65
+ const mapped = toMap(data, field);
66
+ values.keys.active = void 0;
67
+ values.keys.original = [...mapped.keys()];
68
+ values.objects.mapped = mapped;
69
+ values.objects.array = data;
70
+ this.managers.virtualization.update(true);
71
+ }
72
+ async synchronize(data, remove) {
73
+ const { field, values } = this;
74
+ const add = [];
75
+ const updated = [];
76
+ const keys = /* @__PURE__ */ new Set([]);
77
+ const { length } = data;
78
+ for (let index = 0; index < length; index += 1) {
79
+ const object = data[index];
80
+ const key = object[field];
81
+ if (values.objects.mapped.has(key)) updated.push(object);
82
+ else add.push(object);
83
+ keys.add(key);
84
+ }
85
+ if (keys.size === 0) return;
86
+ if (remove ?? false) {
87
+ const toRemove = values.keys.original.filter((key) => !keys.has(key));
88
+ if (toRemove.length > 0) await this.remove(toRemove, false);
89
+ }
90
+ await this.update(updated);
91
+ if (add.length > 0) await this.add(add, false);
92
+ if (add.length > 0 || (remove ?? false)) this.managers.virtualization.update(true);
93
+ }
94
+ async update(data) {
95
+ const { field, managers, values } = this;
96
+ const { length } = data;
97
+ for (let index = 0; index < length; index += 1) {
98
+ const object = data[index];
99
+ const key = object[field];
100
+ const value = values.objects.mapped.get(key);
101
+ if (value != null) {
102
+ values.objects.mapped.set(key, {
103
+ ...value,
104
+ ...object
105
+ });
106
+ managers.row.update(key);
107
+ }
108
+ }
28
109
  }
29
110
  };
30
111
  export { DataManager };
@@ -1,9 +1,9 @@
1
- import { RowComponent } from "../components/row.component.js";
1
+ import { RowComponent, renderRow } from "../components/row.component.js";
2
2
  var RowManager = class {
3
3
  components = /* @__PURE__ */ new Map();
4
4
  height;
5
- constructor(tabela, rowHeight) {
6
- this.tabela = tabela;
5
+ constructor(managers, rowHeight) {
6
+ this.managers = managers;
7
7
  this.height = rowHeight;
8
8
  }
9
9
  destroy() {
@@ -17,5 +17,15 @@ var RowManager = class {
17
17
  }
18
18
  return row;
19
19
  }
20
+ has(key) {
21
+ return this.components.has(key);
22
+ }
23
+ remove(key) {
24
+ this.components.delete(key);
25
+ }
26
+ update(key) {
27
+ const row = this.components.get(key);
28
+ if (row != null) renderRow(this.managers, row);
29
+ }
20
30
  };
21
31
  export { RowManager };
@@ -1,24 +1,22 @@
1
1
  import { removeRow, renderRow } from "../components/row.component.js";
2
2
  import { on } from "@oscarpalmer/toretto/event";
3
- function getRange(tabela, down) {
4
- const { components, managers } = tabela;
5
- const { body } = components;
6
- const { data, rows } = managers;
7
- const { clientHeight, scrollTop } = body.elements.group;
8
- const first = Math.floor(scrollTop / rows.height);
9
- const last = Math.min(data.length - 1, Math.ceil((scrollTop + clientHeight) / rows.height) - 1);
10
- const before = Math.ceil(clientHeight / rows.height) * (down ? 1 : 2);
11
- const after = Math.ceil(clientHeight / rows.height) * (down ? 2 : 1);
3
+ function getRange(down) {
4
+ const { components, managers } = this;
5
+ const { clientHeight, scrollTop } = components.body.elements.group;
6
+ const first = Math.floor(scrollTop / managers.row.height);
7
+ 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);
8
+ const before = Math.ceil(clientHeight / managers.row.height) * (down ? 1 : 2);
9
+ const after = Math.ceil(clientHeight / managers.row.height) * (down ? 2 : 1);
12
10
  const start = Math.max(0, first - before);
13
11
  return {
14
- end: Math.min(data.length - 1, last + after),
12
+ end: Math.min(managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length - 1, last + after),
15
13
  start
16
14
  };
17
15
  }
18
16
  function onScroll() {
19
17
  if (!this.state.active) {
20
18
  requestAnimationFrame(() => {
21
- const top = this.tabela.components.body.elements.group.scrollTop;
19
+ const top = this.components.body.elements.group.scrollTop;
22
20
  this.update(top > this.state.top);
23
21
  this.state.active = false;
24
22
  this.state.top = top;
@@ -38,14 +36,15 @@ var VirtualizationManager = class {
38
36
  top: 0
39
37
  };
40
38
  visible = /* @__PURE__ */ new Map();
41
- constructor(tabela) {
42
- this.tabela = tabela;
43
- this.listener = on(tabela.components.body.elements.group, "scroll", onScroll.bind(this));
39
+ constructor(managers, components) {
40
+ this.managers = managers;
41
+ this.components = components;
42
+ this.listener = on(components.body.elements.group, "scroll", onScroll.bind(this));
44
43
  }
45
44
  destroy() {
46
45
  this.listener();
47
46
  for (const [index, row] of this.visible) {
48
- removeRow(row, this.pool);
47
+ removeRow(this.pool, row);
49
48
  this.visible.delete(index);
50
49
  }
51
50
  this.pool.cells = {};
@@ -60,33 +59,41 @@ var VirtualizationManager = class {
60
59
  delete row.cells[fields[index]];
61
60
  }
62
61
  }
62
+ getFragment() {
63
+ this.fragment ??= document.createDocumentFragment();
64
+ this.fragment.replaceChildren();
65
+ return this.fragment;
66
+ }
63
67
  update(down) {
64
- const { tabela } = this;
65
- const { rows } = tabela.managers;
68
+ const { components, managers, pool, visible } = this;
69
+ components.body.elements.faker.style.height = `${managers.data.size * managers.row.height}px`;
66
70
  const indices = /* @__PURE__ */ new Set();
67
- const range = getRange(tabela, down);
71
+ const range = getRange.call(this, down);
68
72
  for (let index = range.start; index <= range.end; index += 1) indices.add(index);
69
- for (const [index, row] of this.visible) if (!indices.has(index)) {
70
- this.visible.delete(index);
71
- removeRow(row, this.pool);
73
+ let remove = false;
74
+ for (const [index, row] of visible) {
75
+ if (!managers.row.has(row.key) || !indices.has(index)) remove = true;
76
+ if (remove) {
77
+ visible.delete(index);
78
+ removeRow(pool, row);
79
+ }
72
80
  }
73
- this.fragment ??= document.createDocumentFragment();
74
- this.fragment.replaceChildren();
75
- const keys = tabela.managers.data.values.keys.active ?? tabela.managers.data.values.keys.original;
81
+ const fragment = this.getFragment();
82
+ const keys = managers.data.values.keys.active ?? managers.data.values.keys.original;
76
83
  let count = 0;
77
84
  for (let index = range.start; index <= range.end; index += 1) {
78
- if (this.visible.has(index)) continue;
79
- const row = tabela.managers.rows.get(keys[index]);
85
+ if (visible.has(index)) continue;
86
+ const row = managers.row.get(keys[index]);
80
87
  if (row == null) continue;
81
88
  count += 1;
82
- renderRow(tabela, this.pool, row);
83
- this.visible.set(index, row);
89
+ renderRow(managers, row);
90
+ visible.set(index, row);
84
91
  if (row.element != null) {
85
- row.element.style.transform = `translateY(${index * rows.height}px)`;
86
- this.fragment.append(row.element);
92
+ row.element.style.transform = `translateY(${index * managers.row.height}px)`;
93
+ fragment.append(row.element);
87
94
  }
88
95
  }
89
- if (count > 0) tabela.components.body.elements.group[down ? "append" : "prepend"](this.fragment);
96
+ if (count > 0) components.body.elements.group[down ? "append" : "prepend"](fragment);
90
97
  }
91
98
  };
92
99
  export { VirtualizationManager };
File without changes