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